From 8ff9eae3f2ea419de51c349dbc41580fa715e3a9 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 10 Jun 2024 14:03:19 +0200 Subject: [PATCH 01/66] added mavenize method to shorten jar paths in the local maven repository' --- src/org/rascalmpl/uri/URIUtil.java | 2 +- .../uri/file/MavenRepositoryURIResolver.java | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/org/rascalmpl/uri/URIUtil.java b/src/org/rascalmpl/uri/URIUtil.java index 1b0d4ee5566..2bc4fbef1fb 100644 --- a/src/org/rascalmpl/uri/URIUtil.java +++ b/src/org/rascalmpl/uri/URIUtil.java @@ -337,7 +337,7 @@ public static String getURIName(URI uri) { File file = new File(uri.getPath()); return file.getName(); } - + public static String getLocationName(ISourceLocation uri) { File file = new File(uri.getPath()); return file.getName(); diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 45ea030e0ba..8d2bed47fae 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -7,6 +7,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; import org.rascalmpl.uri.jar.JarURIResolver; @@ -217,4 +218,25 @@ public ISourceLocation resolve(ISourceLocation input) throws IOException { } } } + + /** + * Shortens a location of a jar file that points into a local maven repository, and + * leaves all other locations as-is. + * */ + public static ISourceLocation mavenize(ISourceLocation loc) { + loc = URIResolverRegistry.getInstance().logicalToPhysical(loc); + + ISourceLocation repo = URIUtil.createFileLocation(inferMavenRepositoryLocation()); + boolean isFileInRepo = loc.getScheme().equals("file") && URIUtil.relativize(repo, loc).getScheme().equals("relative"); + + if (isFileInRepo) { + String groupId = URIUtil.getParentLocation(URIUtil.getParentLocation(URIUtil.getParentLocation(loc))).getPath().substring(1).replaceAll, "/", "."); + String artifactId = URIUtil.getLocationName(URIUtil.getParentLocation(URIUtil.getParentLocation(loc))); + String version = URIUtil.getLocationName(URIUtil.getParentLocation(loc)); + + return URIUtil.correctLocation("mvn", groupId + "!" + artifactId + "!" + version, ""); + } + + return loc; + } } From 0608349ecd5af8bac17fbcbd987ce4339cb3eafc Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 10 Jun 2024 15:03:40 +0200 Subject: [PATCH 02/66] made mavenize and jarify available to Rascal programmers --- src/org/rascalmpl/library/Location.rsc | 8 +++++ src/org/rascalmpl/library/Prelude.java | 10 ++++++ src/org/rascalmpl/uri/URIUtil.java | 26 ++++++++++++++ .../uri/file/MavenRepositoryURIResolver.java | 35 ++++++++++++------- 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/org/rascalmpl/library/Location.rsc b/src/org/rascalmpl/library/Location.rsc index 50b82dab347..5cebe469580 100644 --- a/src/org/rascalmpl/library/Location.rsc +++ b/src/org/rascalmpl/library/Location.rsc @@ -45,6 +45,14 @@ loc relativize(list[loc] haystack, loc needle) { } } +@synopsis{Shortens an absolute path to a jar inside the local maven repository.} +@javaClass{org.rascalmpl.library.Prelude} +java loc mavenize(loc jar); + +@synopsis{If the location points to a jar file, then this modifies the scheme and the path to point _inside_ of the jar.} +@javaClass{org.rascalmpl.library.Prelude} +java loc jarify(loc jar); + @synopsis{Convert Windows path syntax to a `loc` value} @description{ This conversion supports generic Windows path syntax, including: diff --git a/src/org/rascalmpl/library/Prelude.java b/src/org/rascalmpl/library/Prelude.java index 33036ee01ab..0188bd3a1c2 100644 --- a/src/org/rascalmpl/library/Prelude.java +++ b/src/org/rascalmpl/library/Prelude.java @@ -83,6 +83,8 @@ import org.rascalmpl.uri.ISourceLocationWatcher.ISourceLocationChangeType; import org.rascalmpl.uri.ISourceLocationWatcher.ISourceLocationChanged; import org.rascalmpl.uri.ISourceLocationWatcher.ISourceLocationType; +import org.rascalmpl.uri.file.MavenRepositoryURIResolver; +import org.rascalmpl.uri.jar.JarURIResolver; import org.rascalmpl.uri.LogicalMapResolver; import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; @@ -3608,6 +3610,14 @@ public ISourceLocation resolveLocation(ISourceLocation loc) { } } + public ISourceLocation mavenize(ISourceLocation jar) { + return MavenRepositoryURIResolver.mavenize(jar); + } + + public ISourceLocation jarify(ISourceLocation jar) { + return JarURIResolver.jarify(jar); + } + public ISet findResources(IString fileName) { return resourceProvider.findResources(fileName.getValue()).stream().collect(values.setWriter()); } diff --git a/src/org/rascalmpl/uri/URIUtil.java b/src/org/rascalmpl/uri/URIUtil.java index 2bc4fbef1fb..763a82fb179 100644 --- a/src/org/rascalmpl/uri/URIUtil.java +++ b/src/org/rascalmpl/uri/URIUtil.java @@ -433,6 +433,32 @@ public static ISourceLocation removeOffset(ISourceLocation prev) { public static ISourceLocation createFromURI(String value) throws URISyntaxException { return vf.sourceLocation(createFromEncoded(value)); } + + /** + * Extracts the extension (the characters after the last . in the file name), + * if any, and otherwise returns the empty string. + * @param loc + * @return + */ + public static String getExtension(ISourceLocation loc) { + String path = loc.getPath(); + boolean endsWithSlash = path.endsWith(URIUtil.URI_PATH_SEPARATOR); + if (endsWithSlash) { + path = path.substring(0, path.length() - 1); + } + + if (path.length() > 1) { + int slashIndex = path.lastIndexOf(URIUtil.URI_PATH_SEPARATOR); + int index = path.substring(slashIndex).lastIndexOf('.'); + + if (index != -1) { + return path.substring(slashIndex + index + 1); + } + } + + return ""; + } + public static ISourceLocation changeExtension(ISourceLocation location, String ext) throws URISyntaxException { String path = location.getPath(); boolean endsWithSlash = path.endsWith(URIUtil.URI_PATH_SEPARATOR); diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 8d2bed47fae..2c762b32bcd 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.net.URISyntaxException; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -224,19 +225,29 @@ public ISourceLocation resolve(ISourceLocation input) throws IOException { * leaves all other locations as-is. * */ public static ISourceLocation mavenize(ISourceLocation loc) { - loc = URIResolverRegistry.getInstance().logicalToPhysical(loc); - - ISourceLocation repo = URIUtil.createFileLocation(inferMavenRepositoryLocation()); - boolean isFileInRepo = loc.getScheme().equals("file") && URIUtil.relativize(repo, loc).getScheme().equals("relative"); + try { + loc = URIResolverRegistry.getInstance().logicalToPhysical(loc); - if (isFileInRepo) { - String groupId = URIUtil.getParentLocation(URIUtil.getParentLocation(URIUtil.getParentLocation(loc))).getPath().substring(1).replaceAll, "/", "."); - String artifactId = URIUtil.getLocationName(URIUtil.getParentLocation(URIUtil.getParentLocation(loc))); - String version = URIUtil.getLocationName(URIUtil.getParentLocation(loc)); - - return URIUtil.correctLocation("mvn", groupId + "!" + artifactId + "!" + version, ""); - } + if (!URIUtil.getExtension(loc).equals("jar")) { + return loc; + } + + ISourceLocation repo = URIUtil.createFileLocation(inferMavenRepositoryLocation()); + ISourceLocation relative = URIUtil.relativize(repo, loc); + boolean isFileInRepo = loc.getScheme().equals("file") && relative.getScheme().equals("relative"); - return loc; + if (isFileInRepo) { + String groupId = URIUtil.getParentLocation(URIUtil.getParentLocation(URIUtil.getParentLocation(relative))).getPath().substring(1).replaceAll("/", "."); + String artifactId = URIUtil.getLocationName(URIUtil.getParentLocation(URIUtil.getParentLocation(relative))); + String version = URIUtil.getLocationName(URIUtil.getParentLocation(relative)); + + return URIUtil.correctLocation("mvn", groupId + "!" + artifactId + "!" + version, ""); + } + + return loc; + } + catch (IOException | URISyntaxException e) { + return loc; + } } } From 5a5d5a41958931162c6b30b9409ae9a286d3da8b Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 11 Jun 2024 18:58:35 +0200 Subject: [PATCH 03/66] cleanup of PathConfig and added diagnostics to the dependency resolution and configuration process by adding a messages field to PathConfig --- .../interpreter/utils/RascalManifest.java | 29 +- src/org/rascalmpl/library/util/Eval.java | 22 - .../rascalmpl/library/util/PathConfig.java | 832 ++++++++---------- .../rascalmpl/library/util/Reflective.java | 2 +- src/org/rascalmpl/library/util/Reflective.rsc | 29 +- .../shell/ShellEvaluatorFactory.java | 2 +- .../infrastructure/RascalJUnitTestRunner.java | 2 +- 7 files changed, 392 insertions(+), 526 deletions(-) diff --git a/src/org/rascalmpl/interpreter/utils/RascalManifest.java b/src/org/rascalmpl/interpreter/utils/RascalManifest.java index a23acb73da8..ad21835e462 100644 --- a/src/org/rascalmpl/interpreter/utils/RascalManifest.java +++ b/src/org/rascalmpl/interpreter/utils/RascalManifest.java @@ -66,6 +66,20 @@ public static String getRascalVersionNumber() { return "unknown (due to " + e.getMessage(); } } + + public String getManifestVersionNumber(ISourceLocation project) throws IOException { + Manifest mf = new Manifest(manifest(project)); + + String bundleName = mf.getMainAttributes().getValue("Name"); + if (bundleName != null && bundleName.equals("rascal")) { + String result = mf.getMainAttributes().getValue("Specification-Version"); + if (result != null) { + return result; + } + } + + return "Unknown version for " + project + " (missing MANIFEST.MF or Specification-Version in MANIFEST.MF)"; + } public Manifest getDefaultManifest(String projectName) { Manifest manifest = new Manifest(); @@ -274,21 +288,6 @@ public List getRequiredLibraries(ISourceLocation root) { return getManifestRequiredLibraries(manifest(root)); } - public PathConfig makePathConfig(ISourceLocation root) throws IOException { - List libs = new ArrayList<>(); - List srcs = new ArrayList<>(); - - ISourceLocation binFolder = URIUtil.getChildLocation(root, "bin"); - libs.add(binFolder); - - RascalManifest mf = new RascalManifest(); - for (String src : mf.getSourceRoots(root)) { - srcs.add(URIUtil.getChildLocation(root, src)); - } - - return new PathConfig(srcs, libs, binFolder); - } - public InputStream manifest(JarInputStream stream) { JarEntry next = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); diff --git a/src/org/rascalmpl/library/util/Eval.java b/src/org/rascalmpl/library/util/Eval.java index 6da394f8621..44b3686596d 100644 --- a/src/org/rascalmpl/library/util/Eval.java +++ b/src/org/rascalmpl/library/util/Eval.java @@ -282,28 +282,6 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { return current; } - - private String javaCompilerPathAsString(IList javaCompilerPath) { - StringBuilder b = new StringBuilder(); - - for (IValue elem : javaCompilerPath) { - ISourceLocation loc = (ISourceLocation) elem; - - if (b.length() != 0) { - b.append(File.pathSeparatorChar); - } - - // this is the precondition - assert loc.getScheme().equals("file"); - - // this is robustness in case of experimentation in pom.xml - if ("file".equals(loc.getScheme())) { - b.append(Paths.get(loc.getURI()).toAbsolutePath().toString()); - } - } - - return b.toString(); - } public void reset() { eval.getCurrentModuleEnvironment().reset(); diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 131c3e31c93..a93f53473c3 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -8,9 +8,11 @@ import java.io.StringReader; import java.io.StringWriter; import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,9 +20,11 @@ import org.rascalmpl.interpreter.Configuration; import org.rascalmpl.interpreter.utils.RascalManifest; +import org.rascalmpl.library.Messages; import org.rascalmpl.uri.ILogicalSourceLocationResolver; import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; +import org.rascalmpl.uri.file.MavenRepositoryURIResolver; import org.rascalmpl.uri.jar.JarURIResolver; import org.rascalmpl.values.IRascalValueFactory; import org.rascalmpl.values.ValueFactoryFactory; @@ -39,56 +43,44 @@ import io.usethesource.vallang.type.TypeStore; public class PathConfig { - private static final IValueFactory vf = ValueFactoryFactory.getValueFactory(); private final TypeFactory tf = TypeFactory.getInstance(); private final TypeStore store = new TypeStore(); - // WARNING: these definitions must reflect the definitions in util::Reflective.rsc + // WARNING: these definitions must reflect the definitions in `util::Reflective` private final Type PathConfigType = tf.abstractDataType(store, "PathConfig"); private final Type pathConfigConstructor = tf.constructor(store, PathConfigType, "pathConfig"); - private final List srcs; // List of locations to search for source files - private final List libs; // List of (library) locations to search for derived files - private final List ignores; // List of (library) locations to ignore while compiling - private final List javaCompilerPath; // List of (library) locations to use for the compiler path of generated parsers - private final List classloaders; // List of (library) locations to use to bootstrap classloaders from - - private final ISourceLocation bin; // Global location for derived files outside projects or libraries + private final List srcs; + private final List libs; + private final ISourceLocation bin; + private final List ignores; + private final ISourceLocation generatedSources; + private final List messages; + - private static ISourceLocation defaultStd; - private static List defaultIgnores; - private static List defaultJavaCompilerPath; - private static List defaultClassloaders; - private static ISourceLocation defaultBin; + // defaults are shared here because they occur in different use places. + private static final List defaultIgnores = Collections.emptyList(); + private static final ISourceLocation defaultGeneratedSources = URIUtil.rootLocation("unknown"); + private static final List defaultMessages = Collections.emptyList(); + private static final ISourceLocation defaultBin = URIUtil.rootLocation("unknown"); + private static final List defaultLibs = Collections.emptyList(); + /** implementation detail of communicating with the `mvn` command */ private static final String WINDOWS_ROOT_TRUSTSTORE_TYPE_DEFINITION = "-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT"; public static enum RascalConfigMode { - INTERPETER, + INTERPRETER, COMPILER } - - static { - try { - // Defaults should be in sync with util::Reflective - defaultStd = vf.sourceLocation("lib", "rascal", ""); - defaultBin = vf.sourceLocation("tmp", "", "default-rascal-bin"); - defaultIgnores = Collections.emptyList(); - defaultJavaCompilerPath = computeDefaultJavaCompilerPath(); - defaultClassloaders = computeDefaultClassLoaders(); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - } public PathConfig() { srcs = Collections.emptyList(); ignores = defaultIgnores; bin = defaultBin; - libs = Arrays.asList(defaultStd); - javaCompilerPath = defaultJavaCompilerPath; - classloaders = defaultClassloaders; + libs = Collections.emptyList(); + generatedSources = defaultGeneratedSources; + messages = defaultMessages; } public PathConfig(IConstructor pcfg) throws IOException { @@ -97,129 +89,106 @@ public PathConfig(IConstructor pcfg) throws IOException { libs(pcfg), bin(pcfg), ignores(pcfg), - javaCompilerPath(pcfg), - classloaders(pcfg) + generatedSources(pcfg), + messages(pcfg) ); } - - private static IList classloaders(IConstructor pcfg) { - return getListValueFromConstructor(pcfg, defaultClassloaders, "classloaders"); - } - private static IList javaCompilerPath(IConstructor pcfg) { - return getListValueFromConstructor(pcfg, defaultJavaCompilerPath, "javaCompilerPath"); - } - - private static IList ignores(IConstructor pcfg) { - return getListValueFromConstructor(pcfg, defaultIgnores, "ignores"); - } - - private static IList getListValueFromConstructor(IConstructor pcfg, List def, String label) { - IList val = (IList) pcfg.asWithKeywordParameters().getParameter(label); - return val == null ? def.stream().collect(vf.listWriter()) : val; - } - - private static ISourceLocation bin(IConstructor pcfg) { - ISourceLocation val = (ISourceLocation) pcfg.asWithKeywordParameters().getParameter("bin"); - return val == null ? defaultBin : val; - } - - private static IList libs(IConstructor pcfg) { - return getListValueFromConstructor(pcfg, Arrays.asList(defaultStd), "libs"); - } - - private static IList srcs(IConstructor pcfg) { - return getListValueFromConstructor(pcfg, Collections.emptyList(), "srcs"); - } - - public PathConfig(List srcs, List libs, ISourceLocation bin) throws IOException { + public PathConfig(List srcs, List libs, ISourceLocation bin) { this(srcs, libs, bin, defaultIgnores); } - public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores) throws IOException { - this(srcs, libs, bin, ignores, defaultJavaCompilerPath); + public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores) { + this(srcs, libs, bin, ignores, defaultGeneratedSources); } - public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, List javaCompilerPath) throws IOException { - this(srcs, libs, bin, ignores, javaCompilerPath, defaultClassloaders); + public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, ISourceLocation generatedSources) { + this(srcs, libs, bin, ignores, generatedSources, defaultMessages); } - public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, List javaCompilerPath, List classloaders) throws IOException { + public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, ISourceLocation generatedSources, List messages) { this.srcs = dedup(srcs); this.ignores = dedup(ignores); this.libs = dedup(libs); this.bin = bin; - this.javaCompilerPath = dedup(javaCompilerPath); - this.classloaders = dedup(classloaders); + this.generatedSources = generatedSources; + this.messages = messages; } - public PathConfig(IList srcs, IList libs, ISourceLocation bin) throws IOException{ + public PathConfig(IList srcs, IList libs, ISourceLocation bin) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; this.ignores = defaultIgnores; - this.javaCompilerPath = defaultJavaCompilerPath; - this.classloaders = defaultClassloaders; + this.generatedSources = defaultGeneratedSources; + this.messages = defaultMessages; } - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores) throws IOException{ + public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; this.ignores = initializeLocList(ignores); - this.javaCompilerPath = defaultJavaCompilerPath; - this.classloaders = defaultClassloaders; + this.generatedSources = defaultGeneratedSources; + this.messages = defaultMessages; } - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, IList javaCompilerPath) throws IOException{ + public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; this.ignores = initializeLocList(ignores); - this.javaCompilerPath = initializeLocList(javaCompilerPath); - this.classloaders = defaultClassloaders; + this.generatedSources = generatedSources; + this.messages = defaultMessages; } - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, IList javaCompilerPath, IList classloaders) throws IOException { + public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources, IList messages) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; this.ignores = initializeLocList(ignores); - this.javaCompilerPath = initializeLocList(javaCompilerPath); - this.classloaders = initializeLocList(classloaders); + this.generatedSources = generatedSources; + this.messages = convertMessages(messages); } - private static ISourceLocation parseSourceLocation(String recLib) throws IOException { - return (ISourceLocation) new StandardTextReader().read(vf, new StringReader(recLib)); - } - - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, IList javaCompilerPath, IList classloaders, ISourceLocation repo) throws IOException{ + public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources, IList messages, ISourceLocation repo) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; this.ignores = initializeLocList(ignores); - this.javaCompilerPath = initializeLocList(javaCompilerPath); - this.classloaders = initializeLocList(classloaders); + this.generatedSources = generatedSources; + this.messages = convertMessages(messages); } - public PathConfig parse(String pathConfigString) throws IOException { - try { - IConstructor cons = (IConstructor) new StandardTextReader().read(vf, store, PathConfigType, new StringReader(pathConfigString)); - IWithKeywordParameters kwp = cons.asWithKeywordParameters(); - - IList srcs = (IList) kwp.getParameter("srcs"); - IList libs = (IList) kwp.getParameter("libs"); - ISourceLocation bin = (ISourceLocation) kwp.getParameter("bin"); - - return new PathConfig( - srcs != null ? srcs : vf.list(), - libs != null ? libs : vf.list(), - bin != null ? bin : URIUtil.rootLocation("cwd") - ); - } - catch (FactTypeUseException e) { - throw new IOException(e); - } + private static IList messages(IConstructor pcfg) { + return getListValueFromConstructor(pcfg, defaultMessages, "messages"); + } + + private static ISourceLocation generatedSources(IConstructor pcfg) { + ISourceLocation val = (ISourceLocation) pcfg.asWithKeywordParameters().getParameter("generatedSources"); + return val == null ? defaultGeneratedSources : val; + } + + private static IList ignores(IConstructor pcfg) { + return getListValueFromConstructor(pcfg, defaultIgnores, "ignores"); + } + + private static IList getListValueFromConstructor(IConstructor pcfg, List def, String label) { + IList val = (IList) pcfg.asWithKeywordParameters().getParameter(label); + return val == null ? def.stream().collect(vf.listWriter()) : val; + } + + private static ISourceLocation bin(IConstructor pcfg) { + ISourceLocation val = (ISourceLocation) pcfg.asWithKeywordParameters().getParameter("bin"); + return val == null ? defaultBin : val; + } + + private static IList libs(IConstructor pcfg) { + return getListValueFromConstructor(pcfg, defaultLibs, "libs"); + } + + private static IList srcs(IConstructor pcfg) { + return getListValueFromConstructor(pcfg, Collections.emptyList(), "srcs"); } private static List initializeLocList(IList srcs) { @@ -250,62 +219,36 @@ private static List convertLocs(IList locs){ return result; } - - private static List computeDefaultClassLoaders() throws URISyntaxException { - List result = new ArrayList<>(); - String javaClasspath = System.getProperty("java.class.path"); - if (javaClasspath != null) { - for (String path : javaClasspath.split(File.pathSeparator)) { - result.add(URIUtil.createFileLocation(new File(path).getAbsolutePath())); - } - } - else { - result.add(URIUtil.correctLocation("system", "", "")); - } - return result; - } - private static List computeDefaultJavaCompilerPath() throws URISyntaxException { - List result = new ArrayList<>(); - String classPath = System.getProperty("java.class.path"); - - if (classPath != null) { - for (String path : classPath.split(File.pathSeparator)) { - result.add(URIUtil.createFileLocation(new File(path).getAbsolutePath())); - } - } - - return result; - } + private static List convertMessages(IList locs){ + List result = new ArrayList<>(); + for(IValue p : locs){ + if(p instanceof IConstructor){ + result.add((IConstructor) p); + } else { + throw new RuntimeException("Messages should contain message constructors and not " + p.getClass().getName()); + } + } + + return result; + } String makeFileName(String qualifiedModuleName) { return makeFileName(qualifiedModuleName, "rsc"); } - public static ISourceLocation getDefaultStd(){ - return defaultStd; - } - public static ISourceLocation getDefaultBin(){ return defaultBin; } - public static List getDefaultJavaCompilerPath() { - return Collections.unmodifiableList(defaultJavaCompilerPath); + public static ISourceLocation getDefaultGeneratedSources() { + return defaultGeneratedSources; } - public static IList getDefaultJavaCompilerPathList() { - return convertLocs(defaultJavaCompilerPath); - } - public static IList getDefaultIgnoresList() { return convertLocs(defaultIgnores); } - public static IList getDefaultClassloadersList() { - return convertLocs(defaultClassloaders); - } - private static IList convertLocs(List locs) { IListWriter w = vf.listWriter(); w.appendAll(locs); @@ -316,10 +259,6 @@ public static List getDefaultIgnores(){ return Collections.unmodifiableList(defaultIgnores); } - public static List getDefaultClassloaders() { - return Collections.unmodifiableList(defaultClassloaders); - } - public IValueFactory getValueFactory() { return vf; } @@ -328,64 +267,32 @@ public IList getSrcs() { return vf.list(srcs.toArray(new IValue[0])); } - public IList getJavaCompilerPath() { - return vf.list(javaCompilerPath.toArray(new IValue[0])); + public ISourceLocation getGeneratedSources() { + return generatedSources; } - public IList getClassloaders() { - return vf.list(classloaders.toArray(new IValue[classloaders.size()])); + public IList getMessages() { + return vf.list(messages.toArray(new IValue[messages.size()])); } - public PathConfig addSourceLoc(ISourceLocation dir) { + public PathConfig addSourceLoc(ISourceLocation dir) throws IOException { List extendedsrcs = new ArrayList(srcs); extendedsrcs.add(dir); - try { - return new PathConfig(extendedsrcs, libs, bin, ignores, javaCompilerPath, classloaders); - } - catch (IOException e) { - assert false; - return this; - } - } - - public PathConfig addJavaCompilerPath(ISourceLocation dir) { - List extended = new ArrayList(javaCompilerPath); - extended.add(dir); - try { - return new PathConfig(srcs, libs, bin, ignores, extended, classloaders); - } - catch (IOException e) { - assert false; - return this; - } + return new PathConfig(extendedsrcs, libs, bin, ignores, generatedSources, messages); } - public PathConfig addClassloader(ISourceLocation dir) { - List extended = new ArrayList(classloaders); - extended.add(dir); - try { - return new PathConfig(srcs, libs, bin, ignores, javaCompilerPath, extended); - } - catch (IOException e) { - assert false; - return this; - } + public PathConfig setGeneratedSources(ISourceLocation dir) throws IOException { + return new PathConfig(srcs, libs, bin, ignores, dir, messages); } public IList getIgnores() { return vf.list(ignores.toArray(new IValue[0])); } - public PathConfig addIgnoreLoc(ISourceLocation dir) { + public PathConfig addIgnoreLoc(ISourceLocation dir) throws IOException { List extendedignores = new ArrayList(ignores); extendedignores.add(dir); - try { - return new PathConfig(srcs, libs, bin, extendedignores, javaCompilerPath, classloaders); - } - catch (IOException e) { - assert false; - return this; - } + return new PathConfig(srcs, libs, bin, extendedignores, generatedSources, messages); } public IList getLibs() { @@ -395,7 +302,7 @@ public IList getLibs() { public PathConfig addLibLoc(ISourceLocation dir) throws IOException { List extendedlibs = new ArrayList(libs); extendedlibs.add(dir); - return new PathConfig(srcs, extendedlibs, bin, ignores, javaCompilerPath, classloaders); + return new PathConfig(srcs, extendedlibs, bin, ignores, generatedSources, messages); } /** @@ -419,6 +326,63 @@ public static PathConfig fromSourceProjectMemberRascalManifest(ISourceLocation p return fromSourceProjectRascalManifest(inferProjectRoot(projectMember), mode); } + /* + * Sometimes we need access to a library that is already on the classpath, for example this could + * be rascal-.jar or typepal.jar or rascal-core or rascal-lsp. The IDE or current runtime + * environment of Rascal has provided these dependencies while booting up the JVM using the `-cp` + * parameter. + * + * This function searches for the corresponding jar file by looking for instances of RASCAL.MF files + * with their Project-Name property set to the parameter `projectName`. Then it uses the actual URL + * of the location of the RASCAL.MF file (inside jar or a target folder) to derive the root of the + * given project. + * + * Benefit: After this resolution code has executed, the resulting explicit and transparant jar location is + * useful as an entry in PathConfig instances. + * + * Pitfall: Note however that the current JVM instance can never escape + * from loading classes from the rascal.jar that was given on its classpath. + */ + public static ISourceLocation resolveDependencyFromResourcesOnCurrentClasspath(String projectName) throws IOException { + RascalManifest mf = new RascalManifest(); + Enumeration mfs = PathConfig.class.getClassLoader().getResources(RascalManifest.META_INF_RASCAL_MF); + + for (URL url : Collections.list(mfs)) { + try { + String libName = mf.getProjectName(url.openStream()); + + if (libName != null && libName.equals(projectName)) { + ISourceLocation loc; + + if (url.getProtocol().equals("jar") && url.getPath().startsWith("file:/")) { + // these are the weird jar URLs we get from `getResources` sometimes. We use the URL + // parser to make sense of it and then convert it to an ISourceLocation + loc = vf.sourceLocation("file", null, URIUtil.fromURL(new URL(url.getPath())).getPath()); + + } + else { + // this is typically a target folder + loc = vf.sourceLocation(URIUtil.fromURL(url)); + } + + // unjarify the path + loc = URIUtil.changePath(loc, loc.getPath().replace("!/" + RascalManifest.META_INF_RASCAL_MF, "")); + + return loc; + } + } + catch (IOException | URISyntaxException e) { + throw new FileNotFoundException(e.getMessage()); + } + } + + throw new FileNotFoundException(projectName + " jar could not be located in the current runtime classpath"); + } + + public static ISourceLocation resolveCurrentRascalRuntimeJar() throws IOException { + return resolveDependencyFromResourcesOnCurrentClasspath("rascal"); + } + private static ISourceLocation inferProjectRoot(ISourceLocation member) { ISourceLocation current = member; URIResolverRegistry reg = URIResolverRegistry.getInstance(); @@ -438,171 +402,169 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { return current; } /** - * This will create a PathConfig by learning from the MANIFEST/RASCAL.MF file where the sources - * are, which libraries to reference and which classpath entries to add. If this PathConfig is - * for the interpreter it adds more folders to the source path than if its for the compiler. + * This will create a PathConfig by learning from the `MANIFEST/RASCAL.MF` file where the sources + * are, and from `pom.xml` which libraries to reference. If this PathConfig is + * for the interpreter it adds more folders to the source path than if its for the compiler. In the future + * we'd like the source folders also configured by the pom.xml but for now we read it from RASCAL.MF for + * the sake of efficiency (reading pom.xml requires an XML parse and DOM traversal.) Also we need + * some level of backward compatibility until everybody has moved to using pom.xml. * - * If library dependencies exist for open projects in the same IDE, via the lib://libName, project://libName - * correspondence, then the target and source folders of the projects are added rather then - * the jar files. For compiler configs this works differently than for interpreter configs. - * The latter adds source folders to the sources while the former adds target folders to the libraries. + * If library dependencies exist for _open_ projects in the same IDE, via the `project://` + * correspondence with `mvn://!!`, then the target and source folders of + * those projects are added to the configuration instead of the jar files. + * For compiler configs this works differently than for interpreter configs. + * The latter adds source folders to the `srcs` while the former adds target folders to the `libs`. * * @param manifest the source location of the folder which contains MANIFEST/RASCAL.MF. - * @return - * @throws URISyntaxException + * @param RascalConfigMode.INTERPRETER | RascalConfigMode.COMPILER + * @return a PathConfig instance, fully informed to start initializing a Rascal compiler or interpreter. + * @throws nothing, because all errors are collected in a messages field of the PathConfig. */ - public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifestRoot, RascalConfigMode mode) throws IOException { + public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifestRoot, RascalConfigMode mode) { RascalManifest manifest = new RascalManifest(); URIResolverRegistry reg = URIResolverRegistry.getInstance(); - Set loaderSchemes = reg.getRegisteredClassloaderSchemes(); IRascalValueFactory vf = IRascalValueFactory.getInstance(); String projectName = manifest.getProjectName(manifestRoot); IListWriter libsWriter = vf.listWriter(); IListWriter srcsWriter = vf.listWriter(); - IListWriter classloaders = vf.listWriter(); - Map mavenLibs = new HashMap<>(); + IListWriter messages = vf.listWriter(); if (!projectName.equals("rascal")) { // always add the standard library but not for the project named "rascal" // which contains the source of the standard library - libsWriter.append(URIUtil.correctLocation("lib", "rascal", "")); + try { + libsWriter.append(resolveCurrentRascalRuntimeJar()); + } + catch (IOException e) { + + } } - // target classes always go first - ISourceLocation target = URIUtil.correctLocation("target", projectName, "/"); - classloaders.append(target); + ISourceLocation target = URIUtil.correctLocation("project", projectName, "target/classes"); + ISourceLocation generatedSources = URIUtil.correctLocation("project", projectName, "target/generatedSources"); - // for the Rascal run-time - classloaders.append(URIUtil.correctLocation("system", "", "")); + // This later holds a location of the boot project rascal, in case we depend on that directly in the pom.xml + // Depending on which mode we are in, the configuration will run more (version) sanity checks and configure + // the `libs` differently; all to avoid implicit duplicate and/or inconsistent entries on the `libs` path. + ISourceLocation rascalProject = null; - IList mavenClasspath = getPomXmlCompilerClasspath(manifestRoot); - - // the dependencies in the back - classloaders.appendAll(mavenClasspath); + try { + IList mavenClasspath = getPomXmlCompilerClasspath(manifestRoot); - // this collects Rascal libraries we can find in maven dependencies - for (IValue elem : mavenClasspath) { - ISourceLocation dep = (ISourceLocation) elem; - String libProjectName = manifest.getManifestProjectName(manifest.manifest(dep)); - - if (libProjectName != null) { - mavenLibs.put(libProjectName, JarURIResolver.jarify(dep)); - } - } - - for (String lib : manifest.getRequiredLibraries(manifestRoot)) { - try { - ISourceLocation jar = lib.startsWith("|") ? parseSourceLocation(lib) : URIUtil.getChildLocation(manifestRoot, lib); - ISourceLocation projectLoc = URIUtil.correctLocation("project", jar.getAuthority(), "/"); - - assert jar != null; + // This processes Rascal libraries we can find in maven dependencies, + // adding them to libs or srcs depending on which mode we are in. + // also if a current project is open with the same name, we defer to its + // srcs or target folder instead, for easy development of cross-project + // features in the IDE. + for (IValue elem : mavenClasspath) { + ISourceLocation dep = (ISourceLocation) elem; + String libProjectName = manifest.getManifestProjectName(manifest.manifest(dep)); + ISourceLocation projectLoc = URIUtil.correctLocation("project", libProjectName, ""); + + if (libProjectName.equals("rascal")) { + rascalProject = dep; + } - if (jar.getScheme().equals("lib") && reg.exists(projectLoc)) { - // library dependency to open peer project in the workspace + if (libProjectName != null) { + if (reg.exists(projectLoc)) { + // The project we depend on is available in the current workspace. + // so we configure for using the current state of that project. + PathConfig childConfig = fromSourceProjectRascalManifest(projectLoc, mode); + + switch (mode) { + case INTERPRETER: + srcsWriter.appendAll(childConfig.getSrcs()); + break; + case COMPILER: + libsWriter.append(setTargetScheme(projectLoc)); + break; + } - PathConfig childConfig = fromSourceProjectRascalManifest(projectLoc, mode); + // libraries are transitively collected + libsWriter.appendAll(childConfig.getLibs()); - switch (mode) { - case INTERPETER: - srcsWriter.appendAll(childConfig.getSrcs()); - break; - case COMPILER: - libsWriter.append(setTargetScheme(projectLoc)); - break; + // error messages are transitively collected + messages.appendAll(childConfig.getMessages()); } - - // TODO: do we really want to expose all transitive libraries to the type-checker? - libsWriter.appendAll(childConfig.getLibs()); - classloaders.appendAll(childConfig.getClassloaders()); - } - else { - ISourceLocation jarLoc = jar; - - if (jar.getScheme().equals("lib")) { - String libraryName = jar.getAuthority(); - if (libraryName.equals("rascal")) { - // ignore ourselves - continue; + else { + // just a pre-installed dependency in the local maven repository + if (!reg.exists(dep)) { + messages.append(Messages.error("Declared dependency does not exist: " + dep, getPomXmLocation(manifestRoot))); } - ISourceLocation libraryLoc = mavenLibs.get(libraryName); - if (libraryLoc != null) { - jarLoc = libraryLoc; + switch (mode) { + case COMPILER: + libsWriter.append(dep); + break; + case INTERPRETER: + addLibraryToSourcePath(manifest, reg, srcsWriter, dep); + break; + default: + messages.append(Messages.error("Can not recognize configuration mode (should be COMPILER or INTERPRETER):" + mode, getRascalMfLocation(manifestRoot))); } } + } + } + } + catch (IOException e) { + messages.append(Messages.warning(e.getMessage(), getPomXmlLocation(manifestRoot))); + } - if (!reg.exists(jarLoc)) { - throw new FileNotFoundException(jarLoc.toString()); - } - - switch (mode) { - case COMPILER: - libsWriter.append(jarLoc); - break; - case INTERPETER: - addLibraryToSourcePath(manifest, reg, srcsWriter, jarLoc); - break; - default: - throw new IOException("unknown configuration mode: " + mode); - } - - // if this is not a jar file from the pom, its a new place to find classes - if (jar == jarLoc && loaderSchemes.contains(jar.getScheme())) { - classloaders.append(jar); + try { + if (!projectName.equals("rascal") && rascalProject == null) { + // always add the standard library but not for the project named "rascal" + // which contains the (source of) the standard library, and if we already + // have a dependency on the rascal project we don't add it here either. + libsWriter.append(resolveCurrentRascalRuntimeJar()); + } + else { + if (mode == RascalConfigMode.INTERPRETER) { + // the Rascal interpreter can not escape its own classpath, whether + // or not we configure a different version in the current project's + // pom.xml + RascalManifest rmf = new RascalManifest(); + var builtinRascalProject = reg.logicalToPhysical(resolveCurrentRascalRuntimeJar()); + var builtinVersion = rmf.getManifestVersionNumber(builtinRascalProject); + var dependentRascalProject = reg.logicalToPhysical(rascalProject); + var dependentVersion = rmf.getManifestVersionNumber(dependentRascalProject); + + if (!builtinVersion.equals(dependentVersion)) { + messages.append(Messages.warning("Dependency on Rascal is " + dependentVersion + " while " + builtinVersion + " is effective.", getPomXmlLocation(manifestRoot))); } } } - catch (StackOverflowError e) { - // cyclic project dependencies may cause a stackoverflow - throw new IOException("WARNING: cyclic project dependency between projects " + projectName + " and " + lib, e); + + if (!projectName.equals(URIUtil.getLocationName(manifestRoot))) { + messages.append(Messages.error("Project-Name in RASCAL.MF (" + projectName + ") should be equal to folder name (" + URIUtil.getLocationName(manifestRoot) + ")", getRascalMfLocation(manifestRoot))); } - catch (IOException e) { - System.err.println("WARNING: could not resolve dependency on: " + lib + " because: " + e.getMessage()); - continue; + + if (!manifest.getRequiredLibraries(manifestRoot).isEmpty()) { + messages.append(Messages.info("Required-Libraries in RASCAL.MF are not used anymore. Please use Maven dependencies in pom.xml."), getRascalMfLocation(manifestRoot)); } } - + catch (IOException e) { + messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); + } + for (String srcName : manifest.getSourceRoots(manifestRoot)) { - srcsWriter.append(URIUtil.getChildLocation(manifestRoot, srcName)); + var srcFolder = URIUtil.getChildLocation(manifestRoot, srcName); + + if (!reg.exists(srcFolder) || !reg.isDirectory(srcFolder)) { + messages.append(Messages.error("Source folder " + srcFolder + " does not exist.", getRascalMfLocation(rascalProject))); + } + + srcsWriter.append(srcFolder); } return new PathConfig( srcsWriter.done(), libsWriter.done(), target, - vf.list(), - getDefaultJavaCompilerPathList(), - classloaders.done()); + vf.list(), + generatedSources, + messages.done()); } - public static class LibResolverForMavenDependencies implements ILogicalSourceLocationResolver { - private final String libraryName; - private final ISourceLocation jarLoc; - - public LibResolverForMavenDependencies(String libraryName, ISourceLocation jarLoc) { - this.libraryName = libraryName; - this.jarLoc = jarLoc; - } - - @Override - public ISourceLocation resolve(ISourceLocation input) throws IOException { - if (!libraryName.equals(input.getAuthority())) { - return input; - } - return URIUtil.getChildLocation(jarLoc, input.getPath()); - } - - @Override - public String scheme() { - return "lib"; - } - - @Override - public String authority() { - return libraryName; - } - } - private static void addLibraryToSourcePath(RascalManifest manifest, URIResolverRegistry reg, IListWriter srcsWriter, ISourceLocation jar) { boolean foundSrc = false; @@ -629,65 +591,75 @@ private static ISourceLocation setTargetScheme(ISourceLocation projectLoc) { return projectLoc; } } + + private static ISourceLocation getRascalMfLocation(ISourceLocation project) { + return URIUtil.getChildLocation(project, RascalManifest.META_INF_RASCAL_MF); + } + private static ISourceLocation getPomXmlLocation(ISourceLocation project) { + try { + ISourceLocation pomxml = URIUtil.getChildLocation(project, "pom.xml"); + return URIResolverRegistry.getInstance().logicalToPhysical(pomxml); + } + catch (IOException e) { + assert false : e.getMessage(); + return URIUtil.correctLocation("unknown", "", "pom.xml"); + } + } + /** * See if there is a pom.xml and extract the compile-time classpath from a mvn run * if there is such a file. * @param manifestRoot * @return + * @throws IOException */ - private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) { - try { - ISourceLocation pomxml = URIUtil.getChildLocation(manifestRoot, "pom.xml"); - pomxml = URIResolverRegistry.getInstance().logicalToPhysical(pomxml); - manifestRoot = URIResolverRegistry.getInstance().logicalToPhysical(manifestRoot); + private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) throws IOException { + var pomxml = getPomXmlLocation(manifestRoot); + manifestRoot = URIResolverRegistry.getInstance().logicalToPhysical(manifestRoot); - if (!"file".equals(manifestRoot.getScheme())) { - return vf.list(); - } + if (!"file".equals(manifestRoot.getScheme())) { + return vf.list(); + } - if (!URIResolverRegistry.getInstance().exists(pomxml)) { - return vf.list(); - } + if (!URIResolverRegistry.getInstance().exists(pomxml)) { + return vf.list(); + } - String mvnCommand = computeMavenCommandName(); + String mvnCommand = computeMavenCommandName(); - installNecessaryMavenPlugins(mvnCommand); + installNecessaryMavenPlugins(mvnCommand); - // Note how we try to do this "offline" using the "-o" flag - ProcessBuilder processBuilder = new ProcessBuilder(mvnCommand, - "--batch-mode", - "-o", - "dependency:build-classpath", - "-DincludeScope=compile", - trustStoreFix() - ); - - processBuilder.directory(new File(manifestRoot.getPath())); - processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home", System.getenv("JAVA_HOME"))); + // Note how we try to do this "offline" using the "-o" flag + ProcessBuilder processBuilder = new ProcessBuilder(mvnCommand, + "--batch-mode", + "-o", + "dependency:build-classpath", + "-DincludeScope=compile", + trustStoreFix() + ); - Process process = processBuilder.start(); + processBuilder.directory(new File(manifestRoot.getPath())); + processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home", System.getenv("JAVA_HOME"))); - try (BufferedReader processOutputReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - return processOutputReader.lines() - .filter(line -> !line.startsWith("[")) - .filter(line -> !line.contains("-----")) - .flatMap(line -> Arrays.stream(line.split(File.pathSeparator))) - .filter(fileName -> new File(fileName).exists()) - .map(elem -> { - try { - return URIUtil.createFileLocation(elem); - } - catch (URISyntaxException e) { - return null; - } - }) - .filter(e -> e != null) - .collect(vf.listWriter()); - } - } - catch (IOException e) { - return vf.list(); + Process process = processBuilder.start(); + + try (BufferedReader processOutputReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + return processOutputReader.lines() + .filter(line -> !line.startsWith("[")) + .filter(line -> !line.contains("-----")) + .flatMap(line -> Arrays.stream(line.split(File.pathSeparator))) + .filter(fileName -> new File(fileName).exists()) + .map(elem -> { + try { + return MavenRepositoryURIResolver.mavenize(URIUtil.createFileLocation(elem)); + } + catch (URISyntaxException e) { + return null; + } + }) + .filter(e -> e != null) + .collect(vf.listWriter()); } } @@ -704,7 +676,7 @@ private static String computeMavenCommandName() { } } - private static void installNecessaryMavenPlugins(String mvnCommand) { + private static void installNecessaryMavenPlugins(String mvnCommand) throws IOException { try { ProcessBuilder processBuilder = new ProcessBuilder(mvnCommand, "-q", @@ -720,8 +692,8 @@ private static void installNecessaryMavenPlugins(String mvnCommand) { throw new IOException("mvn dependency:get returned non-zero"); } } - catch (IOException | InterruptedException e) { - System.err.println("[WARNING] Could not install exec-maven-plugin; classpath resolution may be incomplete hereafter: " + e.getMessage()); + catch (InterruptedException e) { + throw new IOException(e); } } @@ -737,111 +709,10 @@ String makeFileName(String qualifiedModuleName, String extension) { return qualifiedModuleName.replaceAll("::", "/") + "." + extension; } - ISourceLocation getModuleLoc(String qualifiedModuleName) throws IOException { - ISourceLocation result = resolveModule(qualifiedModuleName); - if(result == null){ - throw new IOException("Module " + qualifiedModuleName + " not found"); - } - return result; - } - - public ISourceLocation resolveModule(String qualifiedModuleName) { - String fileName = makeFileName(qualifiedModuleName); - for(ISourceLocation dir : srcs){ - ISourceLocation fileLoc; - try { - getFullURI(fileName, dir); - fileLoc = getFullURI(fileName, dir); - if(URIResolverRegistry.getInstance().exists(fileLoc)){ - return fileLoc; - } - } - catch (URISyntaxException e) { - return null; - } - } - return null; - } - - public String getModuleName(ISourceLocation moduleLoc) throws IOException{ - String modulePath = moduleLoc.getPath(); - if(!modulePath.endsWith(".rsc")){ - throw new IOException("Not a Rascal source file: " + moduleLoc); - } - - if (moduleLoc.getScheme().equals("std") || moduleLoc.getScheme().equals("lib")) { - return pathToModulename(modulePath, "/"); - } - - for(ISourceLocation dir : srcs){ - if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ - return pathToModulename(modulePath, dir.getPath()); - } - } - - for (ISourceLocation dir : libs) { - if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ - return pathToModulename(modulePath, dir.getPath()); - } - } - - throw new IOException("No module name found for " + moduleLoc + "\n" + this); - - } - - private String pathToModulename(String modulePath, String folder) { - String moduleName = modulePath.replaceFirst(folder, "").replace(".rsc", ""); - if(moduleName.startsWith("/")){ - moduleName = moduleName.substring(1, moduleName.length()); - } - return moduleName.replace("/", "::"); - } - - private String moduleToDir(String module) { - return module.replaceAll(Configuration.RASCAL_MODULE_SEP, Configuration.RASCAL_PATH_SEP); - } - - private ISourceLocation getFullURI(String path, ISourceLocation dir) throws URISyntaxException { - return URIUtil.getChildLocation(dir, path); - } - - public List listModuleEntries(String moduleRoot) { - assert !moduleRoot.endsWith("::"); - final URIResolverRegistry reg = URIResolverRegistry.getInstance(); - try { - String modulePath = moduleToDir(moduleRoot); - List result = new ArrayList<>(); - for (ISourceLocation dir : srcs) { - ISourceLocation full = getFullURI(modulePath, dir); - if (reg.exists(full)) { - try { - String[] entries = reg.listEntries(full); - if (entries == null) { - continue; - } - for (String module: entries ) { - if (module.endsWith(Configuration.RASCAL_FILE_EXT)) { - result.add(module.substring(0, module.length() - Configuration.RASCAL_FILE_EXT.length())); - } - else if (module.indexOf('.') == -1 && reg.isDirectory(getFullURI(module, full))) { - // a sub folder path - result.add(module + "::"); - } - } - } - catch (IOException e) { - } - } - } - if (result.size() > 0) { - return result; - } - return null; - } catch (URISyntaxException e) { - return null; - } - } - + /** + * Convert PathConfig Java object to pathConfig Rascal constructor for use + * in Rascal code or for serialization and printing. + */ public IConstructor asConstructor() { Map config = new HashMap<>(); @@ -849,20 +720,25 @@ public IConstructor asConstructor() { config.put("ignores", getIgnores()); config.put("bin", getBin()); config.put("libs", getLibs()); - config.put("javaCompilerPath", getJavaCompilerPath()); - config.put("classloaders", getClassloaders()); + config.put("generatedSources", getGeneratedSources()); + config.put("messages", getMessages()); return vf.constructor(pathConfigConstructor, new IValue[0], config); } + /** + * Overview of the contents of the current configuration for debugging purposes. + * Not necessarily for end-user UI, although it's better than nothing. + */ public String toString(){ StringWriter w = new StringWriter(); - w.append("srcs: ").append(getSrcs().toString()).append("\n") - .append("ignores: ").append(getIgnores().toString()).append("\n") - .append("libs: ").append(getLibs().toString()).append("\n") - .append("bin: ").append(getBin().toString()).append("\n") - .append("classpath: ").append(getJavaCompilerPath().toString()).append("\n") - .append("loaders: ").append(getClassloaders().toString()).append("\n") + w.append("Path configuration items:") + .append("srcs: ").append(getSrcs().toString()).append("\n") + .append("ignores: ").append(getIgnores().toString()).append("\n") + .append("libs: ").append(getLibs().toString()).append("\n") + .append("bin: ").append(getBin().toString()).append("\n") + .append("generatedSources:").append(getGeneratedSources().toString()).append("\n") + .append("messages: ").append(getMessages().toString()).append("\n") ; return w.toString(); diff --git a/src/org/rascalmpl/library/util/Reflective.java b/src/org/rascalmpl/library/util/Reflective.java index 44bb23ce3b1..1b4d4862b05 100644 --- a/src/org/rascalmpl/library/util/Reflective.java +++ b/src/org/rascalmpl/library/util/Reflective.java @@ -88,7 +88,7 @@ public IString getLineSeparator() { public IConstructor getProjectPathConfig(ISourceLocation projectRoot, IConstructor mode) { try { if (URIResolverRegistry.getInstance().exists(projectRoot)) { - return PathConfig.fromSourceProjectRascalManifest(projectRoot, mode.getName().equals("compiler") ? RascalConfigMode.COMPILER : RascalConfigMode.INTERPETER).asConstructor(); + return PathConfig.fromSourceProjectRascalManifest(projectRoot, mode.getName().equals("compiler") ? RascalConfigMode.COMPILER : RascalConfigMode.INTERPRETER).asConstructor(); } else { throw new FileNotFoundException(projectRoot.toString()); diff --git a/src/org/rascalmpl/library/util/Reflective.rsc b/src/org/rascalmpl/library/util/Reflective.rsc index 07bfeb7c626..0519752c607 100644 --- a/src/org/rascalmpl/library/util/Reflective.rsc +++ b/src/org/rascalmpl/library/util/Reflective.rsc @@ -18,6 +18,7 @@ import List; import ParseTree; import String; import util::FileSystem; +import Message; import lang::rascal::\syntax::Rascal; import lang::manifest::IO; @@ -41,15 +42,27 @@ data RascalConfigMode | interpreter() ; +@synopsis{General configuration (via path references) of a compiler or interpreter.} +@description{ +A PathConfig is the result of dependency resolution and other configuration steps. Typically, +IDEs produce the information to fill a PathConfig, such that language tools can consume it +transparantly. A PathConfig is also a log of the configuration process. + +* `srcs` list of root directories to search for source files; to interpret or to compile. +* `ignores` list of directories and files to not compile or not interpret (these are typically subtracted from the `srcs` tree, or skipped when the compiler arives there.) +* `bin` is the target root directory for the output of a compiler. Typically this directory would be linked into a zip or a jar or an executable file later. +* `libs` is a list of binary dependency files (typically jar files or target folders) on other projects, for checking and linking purposes. +* `messages` is a list of info, warning and error messages informing end-users about the quality of the configuration process. Typically missing dependencies would be reported here, and clashing versions. +} data PathConfig - // Defaults should be in sync with org.rascalmpl.library.util.PathConfig - = pathConfig(list[loc] srcs = [|std:///|], // List of directories to search for source files - list[loc] ignores = [], // List of locations to ignore from the source files - loc bin = |home:///bin/|, // Global directory for derived files outside projects - list[loc] libs = [|lib://rascal/|], // List of directories to search source for derived files - list[loc] javaCompilerPath = [], // TODO: must generate the same defaults as in PathConfig - list[loc] classloaders = [|system:///|] // TODO: must generate the same defaults as in PathConfig - ); + = pathConfig( + list[loc] srcs = [], + list[loc] ignores = [], + loc bin = |unknown:///|, + loc generatedSources = |unknown:///|, + list[loc] libs = [], + list[Message] messages = [] + ); data RascalManifest = rascalManifest( diff --git a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java index 63eafa3da38..6e72ca5336e 100644 --- a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java +++ b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java @@ -69,7 +69,7 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); try { - PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPETER); + PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPRETER); for (IValue path : pcfg.getSrcs()) { evaluator.addRascalSearchPath((ISourceLocation) path); diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java index 383c114b6c5..1a5715cd75b 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java @@ -105,7 +105,7 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); try { - PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPETER); + PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPRETER); for (IValue path : pcfg.getSrcs()) { From 086aa604cdc0c76ca70c2730b9cf336762d35c6b Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 11 Jun 2024 21:09:16 +0200 Subject: [PATCH 04/66] not finished yet but getting there with the PathConfig refurbishing --- src/org/rascalmpl/library/Messages.java | 28 +++++++++++++++++++ .../util/library/RunRascalTestModules.java | 10 +++++++ 2 files changed, 38 insertions(+) create mode 100644 src/org/rascalmpl/library/Messages.java create mode 100644 test/org/rascalmpl/test/util/library/RunRascalTestModules.java diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java new file mode 100644 index 00000000000..c342f793ac5 --- /dev/null +++ b/src/org/rascalmpl/library/Messages.java @@ -0,0 +1,28 @@ +package org.rascalmpl.library; + +import io.usethesource.vallang.ISourceLocation; +import io.usethesource.vallang.IValue; + +/** + * Java API for the messages in the standard library module `Message` + * + * This is the standard format for all error messages in Rascal projects and beyond. + * Since some low-level core code also produces messages that should end up in UI, + * we write here a bridge between the Java and Rascal representation. + * + * TODO Later when the standard library is bootstrapped, this code might be replaced + * by the generated code from the compiler for the `Message` module. + */ +public class Messages { + + public static IValue warning(String message, ISourceLocation loc) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'warning'"); + } + + public static IValue error(String string, ISourceLocation loc) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'error'"); + } + +} diff --git a/test/org/rascalmpl/test/util/library/RunRascalTestModules.java b/test/org/rascalmpl/test/util/library/RunRascalTestModules.java new file mode 100644 index 00000000000..d616320ed04 --- /dev/null +++ b/test/org/rascalmpl/test/util/library/RunRascalTestModules.java @@ -0,0 +1,10 @@ +package org.rascalmpl.test.library; + +import org.junit.runner.RunWith; +import org.rascalmpl.test.infrastructure.RascalJUnitTestPrefix; +import org.rascalmpl.test.infrastructure.RascalJUnitTestRunner; + +@RunWith(RascalJUnitTestRunner.class) +@RascalJUnitTestPrefix("lang::rascal::tests::library") +public class RunRascalTestModules { } + From 37e3c968cc14f5363082010fac8b466b6b4ef52e Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 12 Jun 2024 09:41:38 +0200 Subject: [PATCH 05/66] implemented Messages --- src/org/rascalmpl/library/Messages.java | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index c342f793ac5..a9a4758a33d 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -1,7 +1,13 @@ package org.rascalmpl.library; +import org.rascalmpl.values.IRascalValueFactory; + import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; +import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.type.TypeFactory; +import io.usethesource.vallang.type.TypeStore; + /** * Java API for the messages in the standard library module `Message` @@ -14,15 +20,25 @@ * by the generated code from the compiler for the `Message` module. */ public class Messages { + private static final TypeFactory tf = TypeFactory.getInstance(); + private static final IValueFactory vf = IRascalValueFactory.getInstance(); + private static final TypeStore ts = new TypeStore(); + + // These declarations mirror the data definition in the `Message` root module of the standard library. + private static final io.usethesource.vallang.type.Type Message = tf.abstractDataType(ts, "Message"); + private static final io.usethesource.vallang.type.Type Message_info = tf.constructor(ts, Message, "info", tf.stringType(), "msg", tf.sourceLocationType(), "at"); + private static final io.usethesource.vallang.type.Type Message_warning = tf.constructor(ts, Message, "warning", tf.stringType(), "msg", tf.sourceLocationType(), "at"); + private static final io.usethesource.vallang.type.Type Message_error = tf.constructor(ts, Message, "error", tf.stringType(), "msg", tf.sourceLocationType(), "at"); + + public static IValue info(String message, ISourceLocation loc) { + return vf.constructor(Message_info, vf.string(message), loc); + } public static IValue warning(String message, ISourceLocation loc) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'warning'"); + return vf.constructor(Message_warning, vf.string(message), loc); } - public static IValue error(String string, ISourceLocation loc) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'error'"); + public static IValue error(String message, ISourceLocation loc) { + return vf.constructor(Message_error, vf.string(message), loc); } - } From 4d8ba067edfe9682688e176b3f07b0f422b936ac Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 17 Jun 2024 14:35:34 +0200 Subject: [PATCH 06/66] cleaning up after changing PathConfig. Also removed unused imports here and there --- .../interpreter/utils/RascalManifest.java | 2 -- src/org/rascalmpl/library/util/Eval.java | 7 ++---- .../rascalmpl/library/util/PathConfig.java | 15 +++--------- .../rascalmpl/semantics/dynamic/Module.java | 2 -- src/org/rascalmpl/shell/CommandOptions.java | 20 ++++++---------- .../shell/ShellEvaluatorFactory.java | 24 +++++++------------ ...ascalJUnitParallelRecursiveTestRunner.java | 1 - .../infrastructure/RascalJUnitTestRunner.java | 6 +---- .../classloaders/PathConfigClassLoader.java | 4 ++-- .../rascalmpl/test/parser/StackNodeTest.java | 1 - .../util/library/RunRascalTestModules.java | 2 +- 11 files changed, 25 insertions(+), 59 deletions(-) diff --git a/src/org/rascalmpl/interpreter/utils/RascalManifest.java b/src/org/rascalmpl/interpreter/utils/RascalManifest.java index ad21835e462..da498a568f9 100644 --- a/src/org/rascalmpl/interpreter/utils/RascalManifest.java +++ b/src/org/rascalmpl/interpreter/utils/RascalManifest.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; @@ -18,7 +17,6 @@ import java.util.jar.Manifest; import java.util.zip.ZipEntry; -import org.rascalmpl.library.util.PathConfig; import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; import org.rascalmpl.uri.jar.JarURIResolver; diff --git a/src/org/rascalmpl/library/util/Eval.java b/src/org/rascalmpl/library/util/Eval.java index 44b3686596d..2fd9b3da09b 100644 --- a/src/org/rascalmpl/library/util/Eval.java +++ b/src/org/rascalmpl/library/util/Eval.java @@ -14,12 +14,10 @@ *******************************************************************************/ package org.rascalmpl.library.util; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URISyntaxException; -import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; @@ -51,7 +49,6 @@ import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IInteger; -import io.usethesource.vallang.IList; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IString; import io.usethesource.vallang.IValue; @@ -227,7 +224,7 @@ public RascalRuntime(PathConfig pcfg, InputStream input, OutputStream stderr, Ou eval.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); eval.setMonitor(services); - eval.getConfiguration().setRascalJavaClassPathProperty(javaCompilerPathAsString(pcfg.getJavaCompilerPath())); + eval.getConfiguration().setRascalJavaClassPathProperty(PathConfig.resolveCurrentRascalRuntimeJar().getPath()); eval.setMonitor(services); if (!pcfg.getSrcs().isEmpty()) { @@ -246,7 +243,7 @@ public RascalRuntime(PathConfig pcfg, InputStream input, OutputStream stderr, Ou eval.addRascalSearchPath((ISourceLocation) path); } - ClassLoader cl = new SourceLocationClassLoader(pcfg.getClassloaders(), ShellEvaluatorFactory.class.getClassLoader()); + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibs(), ShellEvaluatorFactory.class.getClassLoader()); eval.addClassLoader(cl); } diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index a93f53473c3..960a100863a 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -5,7 +5,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; -import java.io.StringReader; import java.io.StringWriter; import java.net.URISyntaxException; import java.net.URL; @@ -16,16 +15,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; - -import org.rascalmpl.interpreter.Configuration; import org.rascalmpl.interpreter.utils.RascalManifest; import org.rascalmpl.library.Messages; -import org.rascalmpl.uri.ILogicalSourceLocationResolver; import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; import org.rascalmpl.uri.file.MavenRepositoryURIResolver; -import org.rascalmpl.uri.jar.JarURIResolver; import org.rascalmpl.values.IRascalValueFactory; import org.rascalmpl.values.ValueFactoryFactory; @@ -35,9 +29,6 @@ import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; -import io.usethesource.vallang.IWithKeywordParameters; -import io.usethesource.vallang.exceptions.FactTypeUseException; -import io.usethesource.vallang.io.StandardTextReader; import io.usethesource.vallang.type.Type; import io.usethesource.vallang.type.TypeFactory; import io.usethesource.vallang.type.TypeStore; @@ -244,7 +235,7 @@ public static ISourceLocation getDefaultBin(){ public static ISourceLocation getDefaultGeneratedSources() { return defaultGeneratedSources; } - + public static IList getDefaultIgnoresList() { return convertLocs(defaultIgnores); } @@ -489,7 +480,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes else { // just a pre-installed dependency in the local maven repository if (!reg.exists(dep)) { - messages.append(Messages.error("Declared dependency does not exist: " + dep, getPomXmLocation(manifestRoot))); + messages.append(Messages.error("Declared dependency does not exist: " + dep, getPomXmlLocation(manifestRoot))); } switch (mode) { @@ -539,7 +530,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes } if (!manifest.getRequiredLibraries(manifestRoot).isEmpty()) { - messages.append(Messages.info("Required-Libraries in RASCAL.MF are not used anymore. Please use Maven dependencies in pom.xml."), getRascalMfLocation(manifestRoot)); + messages.append(Messages.info("Required-Libraries in RASCAL.MF are not used anymore. Please use Maven dependencies in pom.xml.", getRascalMfLocation(manifestRoot))); } } catch (IOException e) { diff --git a/src/org/rascalmpl/semantics/dynamic/Module.java b/src/org/rascalmpl/semantics/dynamic/Module.java index 00b88c2cf80..8a58e7a6e3f 100644 --- a/src/org/rascalmpl/semantics/dynamic/Module.java +++ b/src/org/rascalmpl/semantics/dynamic/Module.java @@ -26,8 +26,6 @@ import org.rascalmpl.interpreter.result.Result; import org.rascalmpl.interpreter.result.ResultFactory; import org.rascalmpl.interpreter.utils.Names; -import org.rascalmpl.uri.URIUtil; - import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; diff --git a/src/org/rascalmpl/shell/CommandOptions.java b/src/org/rascalmpl/shell/CommandOptions.java index 5ef047b73f3..525290e3567 100644 --- a/src/org/rascalmpl/shell/CommandOptions.java +++ b/src/org/rascalmpl/shell/CommandOptions.java @@ -71,12 +71,11 @@ enum OptionType {INT, STR, BOOL, LOCS, LOC}; * */ public class CommandOptions { - private static final String CLASSLOADERS_PATH_CONFIG_OPTION = "classloaders"; - private static final String JAVA_COMPILER_PATH_PATH_CONFIG_OPTION = "javaCompilerPath"; private static final String IGNORES_PATH_CONFIG_OPTION = "ignores"; private static final String BIN_PATH_CONFIG_OPTION = "bin"; private static final String LIB_PATH_CONFIG_OPTION = "lib"; - private static final String PROJECT_PATH_CONFIG_OPTION = "project"; + private static final String GENERATED_SOURCES_PATH_CONFIG_OPTION = "generated-sources"; + private static final String PROJECT_PATH_CONFIG_OPTION = "project"; private static final String SRC_PATH_CONFIG_OPTION = "src"; protected TypeFactory tf; @@ -568,9 +567,8 @@ public PathConfig getPathConfig(PathConfig.RascalConfigMode mode) throws IOExcep return new PathConfig(getCommandLocsOption(SRC_PATH_CONFIG_OPTION), getCommandLocsOption(LIB_PATH_CONFIG_OPTION), getCommandLocOption(BIN_PATH_CONFIG_OPTION), - getCommandLocsOption(IGNORES_PATH_CONFIG_OPTION), - getCommandLocsOption(JAVA_COMPILER_PATH_PATH_CONFIG_OPTION), - getCommandLocsOption(CLASSLOADERS_PATH_CONFIG_OPTION)); + getCommandLocsOption(IGNORES_PATH_CONFIG_OPTION) + ); } } @@ -604,13 +602,9 @@ public CommandOptions pathConfigOptions() { .locsDefault(PathConfig.getDefaultIgnoresList()) .help("Add new ignored locations, use multiple --ignores arguments for multiple locations") - .locsOption(JAVA_COMPILER_PATH_PATH_CONFIG_OPTION) - .locsDefault(PathConfig.getDefaultJavaCompilerPathList()) - .help("Add new java classpath location, use multiple --javaCompilerPath options for multiple locations") - - .locsOption(CLASSLOADERS_PATH_CONFIG_OPTION) - .locsDefault(PathConfig.getDefaultClassloadersList()) - .help("Add new java classloader location, use multiple --classloader options for multiple locations") + .locOption(GENERATED_SOURCES_PATH_CONFIG_OPTION) + .locDefault(PathConfig.getDefaultGeneratedSources()) + .help("Add new target location for generated sources") ; diff --git a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java index 6e72ca5336e..452e536e5d9 100644 --- a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java +++ b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java @@ -1,7 +1,6 @@ package org.rascalmpl.shell; import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URISyntaxException; @@ -68,23 +67,18 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio reg.registerLogical(new ProjectURIResolver(projectRoot, projectName)); reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); - try { - PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPRETER); - - for (IValue path : pcfg.getSrcs()) { - evaluator.addRascalSearchPath((ISourceLocation) path); - } + PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPRETER); - for (IValue path : pcfg.getLibs()) { - evaluator.addRascalSearchPath((ISourceLocation) path); - } - - ClassLoader cl = new SourceLocationClassLoader(pcfg.getClassloaders(), ShellEvaluatorFactory.class.getClassLoader()); - evaluator.addClassLoader(cl); + for (IValue path : pcfg.getSrcs()) { + evaluator.addRascalSearchPath((ISourceLocation) path); } - catch (IOException e) { - System.err.println(e); + + for (IValue path : pcfg.getLibs()) { + evaluator.addRascalSearchPath((ISourceLocation) path); } + + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibs(), ShellEvaluatorFactory.class.getClassLoader()); + evaluator.addClassLoader(cl); } /** diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java index 77a199a134e..8cf30986dec 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java @@ -30,7 +30,6 @@ import org.junit.runner.notification.RunNotifier; import org.rascalmpl.interpreter.Evaluator; import org.rascalmpl.interpreter.ITestResultListener; -import org.rascalmpl.interpreter.NullRascalMonitor; import org.rascalmpl.interpreter.TestEvaluator; import org.rascalmpl.interpreter.env.GlobalEnvironment; import org.rascalmpl.interpreter.env.ModuleEnvironment; diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java index b3900222315..4c615019d9e 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java @@ -28,7 +28,6 @@ import org.rascalmpl.debug.IRascalMonitor; import org.rascalmpl.interpreter.Evaluator; import org.rascalmpl.interpreter.ITestResultListener; -import org.rascalmpl.interpreter.NullRascalMonitor; import org.rascalmpl.interpreter.TestEvaluator; import org.rascalmpl.interpreter.env.GlobalEnvironment; import org.rascalmpl.interpreter.env.ModuleEnvironment; @@ -112,16 +111,13 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio evaluator.addRascalSearchPath((ISourceLocation) path); } - ClassLoader cl = new SourceLocationClassLoader(pcfg.getClassloaders(), ShellEvaluatorFactory.class.getClassLoader()); + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibs(), ShellEvaluatorFactory.class.getClassLoader()); evaluator.addClassLoader(cl); } catch (AssertionError e) { e.printStackTrace(); throw e; } - catch (IOException e) { - System.err.println(e); - } } public static ISourceLocation inferProjectRoot(Class clazz) { diff --git a/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java b/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java index f51e91ced27..561f622947a 100644 --- a/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java +++ b/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java @@ -16,11 +16,11 @@ /** * A ClassLoader which finds classes and resources in the - * classloader location list of a PathConfig. @see IClassloaderLocationResolver + * libs location list of a PathConfig. @see IClassloaderLocationResolver * for more information on how we transform ISourceLocations to Classloaders. */ public class PathConfigClassLoader extends SourceLocationClassLoader { public PathConfigClassLoader(PathConfig pcfg, ClassLoader parent) { - super(pcfg.getClassloaders(), parent); + super(pcfg.getLibs(), parent); } } diff --git a/test/org/rascalmpl/test/parser/StackNodeTest.java b/test/org/rascalmpl/test/parser/StackNodeTest.java index bfc52a4f5b8..6b849ca5fa7 100644 --- a/test/org/rascalmpl/test/parser/StackNodeTest.java +++ b/test/org/rascalmpl/test/parser/StackNodeTest.java @@ -3,7 +3,6 @@ import org.junit.Assert; import org.junit.Test; import org.rascalmpl.parser.gtd.stack.EpsilonStackNode; -import org.rascalmpl.parser.gtd.stack.LiteralStackNode; import org.rascalmpl.parser.gtd.stack.filter.ICompletionFilter; import org.rascalmpl.parser.gtd.stack.filter.IEnterFilter; import org.rascalmpl.parser.gtd.stack.filter.follow.AtEndOfLineRequirement; diff --git a/test/org/rascalmpl/test/util/library/RunRascalTestModules.java b/test/org/rascalmpl/test/util/library/RunRascalTestModules.java index d616320ed04..b5f36bcf3b0 100644 --- a/test/org/rascalmpl/test/util/library/RunRascalTestModules.java +++ b/test/org/rascalmpl/test/util/library/RunRascalTestModules.java @@ -1,4 +1,4 @@ -package org.rascalmpl.test.library; +package org.rascalmpl.test.util.library; import org.junit.runner.RunWith; import org.rascalmpl.test.infrastructure.RascalJUnitTestPrefix; From b212c7efb3db5cd6a6c4be4ab5236c774a45bfe0 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 17 Jun 2024 14:45:31 +0200 Subject: [PATCH 07/66] removed the lib:/// scheme from the implementation --- src/org/rascalmpl/interpreter/Evaluator.java | 1 + src/org/rascalmpl/shell/ModuleRunner.java | 2 +- .../libraries/RascalLibraryURIResolver.java | 262 ------------------ src/org/rascalmpl/uri/resolvers.config | 1 - 4 files changed, 2 insertions(+), 264 deletions(-) delete mode 100644 src/org/rascalmpl/uri/libraries/RascalLibraryURIResolver.java diff --git a/src/org/rascalmpl/interpreter/Evaluator.java b/src/org/rascalmpl/interpreter/Evaluator.java index 06023a97fd9..69901238b7e 100755 --- a/src/org/rascalmpl/interpreter/Evaluator.java +++ b/src/org/rascalmpl/interpreter/Evaluator.java @@ -1167,6 +1167,7 @@ public Result eval(IRascalMonitor monitor, Declaration declaration) { } public void doImport(IRascalMonitor monitor, String... string) { + assert monitor != null; IRascalMonitor old = setMonitor(monitor); interrupt = false; try { diff --git a/src/org/rascalmpl/shell/ModuleRunner.java b/src/org/rascalmpl/shell/ModuleRunner.java index 63ff6c51530..91cea6bb14b 100644 --- a/src/org/rascalmpl/shell/ModuleRunner.java +++ b/src/org/rascalmpl/shell/ModuleRunner.java @@ -27,7 +27,7 @@ public void run(String args[]) throws IOException { } module = module.replaceAll("/", "::"); - eval.doImport(null, module); + eval.doImport(eval.getMonitor(), module); String[] realArgs = new String[args.length - 1]; System.arraycopy(args, 1, realArgs, 0, args.length - 1); diff --git a/src/org/rascalmpl/uri/libraries/RascalLibraryURIResolver.java b/src/org/rascalmpl/uri/libraries/RascalLibraryURIResolver.java deleted file mode 100644 index f1c8b1dd656..00000000000 --- a/src/org/rascalmpl/uri/libraries/RascalLibraryURIResolver.java +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright (c) 2019, Jurgen J. Vinju, Centrum Wiskunde & Informatica (NWOi - CWI) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.rascalmpl.uri.libraries; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.util.Collections; -import java.util.Enumeration; -import java.util.concurrent.ConcurrentHashMap; - -import org.checkerframework.checker.nullness.qual.Nullable; -import org.rascalmpl.interpreter.utils.RascalManifest; -import org.rascalmpl.uri.ISourceLocationInput; -import org.rascalmpl.uri.URIResolverRegistry; -import org.rascalmpl.uri.URIUtil; -import org.rascalmpl.uri.classloaders.IClassloaderLocationResolver; -import org.rascalmpl.values.IRascalValueFactory; -import org.rascalmpl.values.ValueFactoryFactory; - -import io.usethesource.vallang.ISourceLocation; -import io.usethesource.vallang.IValueFactory; - -/** - * The goal of this resolver is to provide |lib://<libName>/| for every Rascal library available in the current run-time environment. - * To do this, it searches for META-INF/RASCAL.MF files in 2 places, and checks if the Project-Name inside of that file is equal to <libName>: - *
    - *
  • |plugin://<libName>| is probed first, in order to give precedence to plugins loaded by application containers such as OSGI;
  • - *
  • Finally ClassLoader.getResources is probed to resolve to |jar+file://path-to-jar-on-classpath!/| if a RASCAL.MF can be found there with the proper Project-Name in it. So this only searches in the JVM start-up classpath via its URLClassLoaders, ignoring plugin mechanisms like OSGI and the like.
  • - *
- *

CAVEAT 1: this resolver caches the first resolution (plugin or jarfile) and does not rescind it afterwards even if the locations - * cease to exist. This might happen due to plugin unloading. To re-initialize an - * already resolved |lib://<libName>| path, either the JVM must be reloaded (restart the IDE) or the current class must be reloaded - * (restart the plugin which loaded the Rascal run-time). TODO FIXME by allowing re-initialization of this entire resolver by the URIResolverRegistry.

- *

CAVEAT 2: it is up to the respective run-time environments (Eclipse, OSGI, MVN, Spring, etc.) to provide the respective implementations - * of ISourceLocation input for the plugin:// scheme. If it is not provided, this resolver only resolves to resources - * which can be found via the System classloader.

- */ -public class RascalLibraryURIResolver implements ISourceLocationInput, IClassloaderLocationResolver { - private final ConcurrentHashMap classpathLibraries = new ConcurrentHashMap<>(); - private final ConcurrentHashMap resolvedLibraries = new ConcurrentHashMap<>(); - private final URIResolverRegistry reg; - - public RascalLibraryURIResolver(URIResolverRegistry reg) { - this.reg = reg; - - try { - IValueFactory vf = ValueFactoryFactory.getValueFactory(); - RascalManifest mf = new RascalManifest(); - Enumeration mfs = getClass().getClassLoader().getResources(RascalManifest.META_INF_RASCAL_MF); - - Collections.list(mfs).forEach(url -> { - try { - String libName = mf.getProjectName(url.openStream()); - - if (libName != null && !libName.isEmpty()) { - ISourceLocation loc; - - if (url.getProtocol().equals("jar") && url.getPath().startsWith("file:/")) { - loc = vf.sourceLocation("jar+file", null, URIUtil.fromURL(new URL(url.getPath())).getPath()); - } - else { - loc = vf.sourceLocation(URIUtil.fromURL(url)); - } - - loc = URIUtil.changePath(loc, loc.getPath().replace(RascalManifest.META_INF_RASCAL_MF, "")); - - registerLibrary("detected", classpathLibraries, libName, loc); - } - } - catch (IOException | URISyntaxException e) { - System.err.println("WARNING: could not load Rascal manifest for library resolution of: " + url); - e.printStackTrace(); - } - }); - } - catch (IOException e) { - System.err.println("WARNING: could not resolve any Rascal library locations"); - e.printStackTrace(); - } - } - - private void registerLibrary(String event, ConcurrentHashMap libs, String libName, ISourceLocation loc) { - /* we want the first match, just like the classpath, so always using the old value */ - if (libs.merge(libName, loc, (o, n) -> o) == loc) { - /* now we have a new one: report it */ - System.err.println("INFO: " + event + " |lib://" + libName + "| at " + loc); - } - } - - /** - * Resolve a lib location to either a plugin or a local classpath location, in that order of precedence. - */ - private @Nullable ISourceLocation resolve(ISourceLocation uri) { - String libName = uri.getAuthority(); - - if (libName == null || libName.isEmpty()) { - return null; - } - - // if we resolved this library before, we stick with that initial resolution for efficiency's sake - ISourceLocation resolved = resolvedLibraries.get(libName); - if (resolved != null) { - return inheritPositions(uri, URIUtil.getChildLocation(resolved, uri.getPath())); - } - - // then we try plugin libraries, taking precedence over classpath libraries - ISourceLocation plugin = deferToScheme(uri, "plugin"); - if (plugin != null) { - return plugin; - } - - // finally we try the classpath libraries - ISourceLocation classpath = classpathLibraries.get(libName); - if (classpath != null) { - return resolvedLocation(uri, libName, classpath); - } - - return null; - } - - /** - * Tries to find a RASCAL.MF file in the deferred scheme's root and if it's present, the - * prefix is cached and the child location is returned. - */ - private ISourceLocation deferToScheme(ISourceLocation uri, String scheme) { - String libName = uri.getAuthority(); - ISourceLocation libRoot = URIUtil.correctLocation(scheme, libName, ""); - - if (isValidLibraryRoot(libRoot)) { - return resolvedLocation(uri, libName, libRoot); - } - else { - return null; - } - } - - /** - * Check if this root contains a valid RASCAL.MF file - */ - private boolean isValidLibraryRoot(ISourceLocation libRoot) { - if (reg.exists(URIUtil.getChildLocation(libRoot, RascalManifest.META_INF_RASCAL_MF))) { - assert new RascalManifest().getProjectName(libRoot).equals(libRoot.getAuthority()) - : "Project-Name in RASCAL.MF does not align with authority of the " + libRoot.getScheme() + " scheme"; - return true; - } - - return false; - } - - /** - * compute the resolved child location and cache the prefix as a side-effect for a future fast path - */ - private ISourceLocation resolvedLocation(ISourceLocation uri, String libName, ISourceLocation deferredLoc) { - registerLibrary("resolved", resolvedLibraries, libName, deferredLoc); - return inheritPositions(uri, URIUtil.getChildLocation(deferredLoc, uri.getPath())); - } - - private static ISourceLocation inheritPositions(ISourceLocation uri, ISourceLocation resolved) { - if (uri.hasOffsetLength()) { - if (uri.hasLineColumn()) { - return IRascalValueFactory.getInstance().sourceLocation(resolved, uri.getOffset(), uri.getLength(), uri.getBeginLine(), uri.getEndLine(), uri.getBeginColumn(), uri.getEndColumn()); - } - else { - return IRascalValueFactory.getInstance().sourceLocation(resolved, uri.getOffset(), uri.getLength()); - } - } - else { - return resolved; - } - } - - /** - * Resolve a location and if not possible throw an exception - */ - private ISourceLocation safeResolve(ISourceLocation uri) throws IOException { - ISourceLocation resolved = resolve(uri); - if (resolved == null) { - throw new IOException("lib:// resolver could not resolve " + uri); - } - return resolved; - } - - @Override - public InputStream getInputStream(ISourceLocation uri) throws IOException { - return reg.getInputStream(safeResolve(uri)); - } - - @Override - public Charset getCharset(ISourceLocation uri) throws IOException { - return reg.getCharset(safeResolve(uri)); - } - - @Override - public boolean exists(ISourceLocation uri) { - ISourceLocation resolved = resolve(uri); - if (resolved == null) { - return false; - } - return reg.exists(resolved); - } - - @Override - public long lastModified(ISourceLocation uri) throws IOException { - return reg.lastModified(safeResolve(uri)); - } - - @Override - public boolean isDirectory(ISourceLocation uri) { - try { - return URIResolverRegistry.getInstance().isDirectory(safeResolve(uri)); - } catch (IOException e) { - return false; - } - } - - @Override - public boolean isFile(ISourceLocation uri) { - try { - return URIResolverRegistry.getInstance().isFile(safeResolve(uri)); - } catch (IOException e) { - return false; - } - } - - @Override - public String[] list(ISourceLocation uri) throws IOException { - return reg.listEntries(safeResolve(uri)); - } - - @Override - public String scheme() { - return "lib"; - } - - @Override - public boolean supportsHost() { - return false; - } - - @Override - public ClassLoader getClassLoader(ISourceLocation loc, ClassLoader parent) throws IOException { - ISourceLocation resolved = resolve(loc); - if (resolved != null) { - return reg.getClassLoader(resolved, parent); - } - - throw new IOException("Can not resolve classloader for " + loc); - } -} diff --git a/src/org/rascalmpl/uri/resolvers.config b/src/org/rascalmpl/uri/resolvers.config index a0f096180ce..2b599b78ccc 100644 --- a/src/org/rascalmpl/uri/resolvers.config +++ b/src/org/rascalmpl/uri/resolvers.config @@ -14,5 +14,4 @@ org.rascalmpl.uri.file.CurrentWorkingDriveResolver org.rascalmpl.uri.file.UNCResolver org.rascalmpl.uri.file.SystemPathURIResolver org.rascalmpl.uri.libraries.MemoryResolver -org.rascalmpl.uri.libraries.RascalLibraryURIResolver From f87980390c08cb09f20b20e6fbbeddaf4d6cf4c7 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 17 Jun 2024 14:55:17 +0200 Subject: [PATCH 08/66] added target folder back to the classpath for loading Java classes --- src/org/rascalmpl/library/util/Eval.java | 2 +- src/org/rascalmpl/library/util/PathConfig.java | 4 ++++ src/org/rascalmpl/shell/ShellEvaluatorFactory.java | 2 +- .../rascalmpl/test/infrastructure/RascalJUnitTestRunner.java | 2 +- src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/org/rascalmpl/library/util/Eval.java b/src/org/rascalmpl/library/util/Eval.java index 2fd9b3da09b..a73acca0f0a 100644 --- a/src/org/rascalmpl/library/util/Eval.java +++ b/src/org/rascalmpl/library/util/Eval.java @@ -243,7 +243,7 @@ public RascalRuntime(PathConfig pcfg, InputStream input, OutputStream stderr, Ou eval.addRascalSearchPath((ISourceLocation) path); } - ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibs(), ShellEvaluatorFactory.class.getClassLoader()); + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); eval.addClassLoader(cl); } diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 960a100863a..987f056fbf2 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -289,6 +289,10 @@ public PathConfig addIgnoreLoc(ISourceLocation dir) throws IOException { public IList getLibs() { return vf.list(libs.toArray(new IValue[0])); } + + public IList getLibsAndTarget() { + return getLibs().append(getBin()); + } public PathConfig addLibLoc(ISourceLocation dir) throws IOException { List extendedlibs = new ArrayList(libs); diff --git a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java index 452e536e5d9..3c42de70f8e 100644 --- a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java +++ b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java @@ -77,7 +77,7 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio evaluator.addRascalSearchPath((ISourceLocation) path); } - ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibs(), ShellEvaluatorFactory.class.getClassLoader()); + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); evaluator.addClassLoader(cl); } diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java index 4c615019d9e..d0967460517 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java @@ -111,7 +111,7 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio evaluator.addRascalSearchPath((ISourceLocation) path); } - ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibs(), ShellEvaluatorFactory.class.getClassLoader()); + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); evaluator.addClassLoader(cl); } catch (AssertionError e) { diff --git a/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java b/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java index 561f622947a..9b9b1b89b5c 100644 --- a/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java +++ b/src/org/rascalmpl/uri/classloaders/PathConfigClassLoader.java @@ -21,6 +21,6 @@ */ public class PathConfigClassLoader extends SourceLocationClassLoader { public PathConfigClassLoader(PathConfig pcfg, ClassLoader parent) { - super(pcfg.getLibs(), parent); + super(pcfg.getLibsAndTarget(), parent); } } From 3034ebdc861df8667d6fc99eb7dd936dd1d6c390 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 24 Jun 2024 20:01:06 +0200 Subject: [PATCH 09/66] the shell evaluator factory and junit evaluator creator now print the errors that PathConfig creation detects --- src/org/rascalmpl/library/Messages.java | 76 +++++++++++++++++++ .../shell/ShellEvaluatorFactory.java | 5 +- .../infrastructure/RascalJUnitTestRunner.java | 5 +- 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index a9a4758a33d..857d4dfaa5e 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -1,8 +1,18 @@ package org.rascalmpl.library; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.rascalmpl.library.util.PathConfig; import org.rascalmpl.values.IRascalValueFactory; +import io.usethesource.vallang.IConstructor; +import io.usethesource.vallang.IList; +import io.usethesource.vallang.ISet; 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.TypeFactory; @@ -41,4 +51,70 @@ public static IValue warning(String message, ISourceLocation loc) { public static IValue error(String message, ISourceLocation loc) { return vf.constructor(Message_error, vf.string(message), loc); } + + public static void write(IList messages, PrintWriter out) { + int maxLine = 0; + int maxColumn = 0; + boolean hasErrors = false; + + for (IValue error : messages) { + ISourceLocation loc = (ISourceLocation) ((IConstructor) error).get("at"); + if (loc.hasLineColumn()) { + maxLine = Math.max(loc.getBeginLine(), maxLine); + maxColumn = Math.max(loc.getBeginColumn(), maxColumn); + } + } + + int lineWidth = (int) Math.log10(maxLine + 1) + 1; + int colWidth = (int) Math.log10(maxColumn + 1) + 1; + + Stream sortedStream = messages.stream() + .map(IConstructor.class::cast) + .sorted((m1, m2) -> { + ISourceLocation l1 = (ISourceLocation) m1.get("at"); + ISourceLocation l2 = (ISourceLocation) m2.get("at"); + + if (l1.getBeginLine() == l2.getBeginLine()) { + return Integer.compare(l1.getBeginColumn(), l2.getBeginColumn()); + } + else { + return Integer.compare(l1.getBeginLine(), l2.getBeginLine()); + } + }); + + for (IConstructor msg : sortedStream.collect(Collectors.toList())) { + String type = msg.getName(); + boolean isError = type.equals("error"); + boolean isWarning = type.equals("warning"); + + ISourceLocation loc = (ISourceLocation) msg.get("at"); + int col = 0; + int line = 0; + if (loc.hasLineColumn()) { + col = loc.getBeginColumn(); + line = loc.getBeginLine(); + } + + String output + = loc.getPath() + + ":" + + String.format("%0" + lineWidth + "d", line) + + ":" + + String.format("%0" + colWidth + "d", col) + + ": " + + ((IString) msg.get("msg")).getValue(); + + if (isError) { + out.println("[ERROR] " + output); + } + else if (isWarning) { + out.println("[WARNING]" + output) + } + else { + out.println("[INFO] " + output); + } + } + + return; + } } diff --git a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java index 3c42de70f8e..095bc7705b9 100644 --- a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java +++ b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java @@ -11,6 +11,7 @@ import org.rascalmpl.interpreter.env.ModuleEnvironment; import org.rascalmpl.interpreter.load.StandardLibraryContributor; import org.rascalmpl.interpreter.utils.RascalManifest; +import org.rascalmpl.library.Messages; import org.rascalmpl.library.util.PathConfig; import org.rascalmpl.library.util.PathConfig.RascalConfigMode; import org.rascalmpl.uri.URIResolverRegistry; @@ -78,7 +79,9 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio } ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); - evaluator.addClassLoader(cl); + evaluator.addClassLoader(cl); + + Messages.write(pcfg.getMessages(), evaluator.getOutPrinter()); } /** diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java index d6b02c7875b..b2c3f94d953 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java @@ -34,6 +34,7 @@ import org.rascalmpl.interpreter.load.StandardLibraryContributor; import org.rascalmpl.interpreter.result.AbstractFunction; import org.rascalmpl.interpreter.utils.RascalManifest; +import org.rascalmpl.library.Messages; import org.rascalmpl.library.util.PathConfig; import org.rascalmpl.library.util.PathConfig.RascalConfigMode; import org.rascalmpl.shell.RascalShell; @@ -111,12 +112,14 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPRETER); for (IValue path : pcfg.getSrcs()) { - evaluator.addRascalSearchPath((ISourceLocation) path); } ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); evaluator.addClassLoader(cl); + + Messages.write(pcfg.getMessages(), evaluator.getOutPrinter()); + } catch (AssertionError e) { e.printStackTrace(); From e3248de0fbff66379ed0a5ca089550de2807e4c4 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 24 Jun 2024 20:03:54 +0200 Subject: [PATCH 10/66] some cleanup --- src/org/rascalmpl/library/Messages.java | 5 +---- .../rascalmpl/repl/TerminalProgressBarMonitor.java | 14 +------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index 857d4dfaa5e..388edc3b7aa 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -1,16 +1,13 @@ package org.rascalmpl.library; -import java.io.PrintStream; import java.io.PrintWriter; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.rascalmpl.library.util.PathConfig; import org.rascalmpl.values.IRascalValueFactory; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IList; -import io.usethesource.vallang.ISet; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IString; import io.usethesource.vallang.IValue; @@ -108,7 +105,7 @@ public static void write(IList messages, PrintWriter out) { out.println("[ERROR] " + output); } else if (isWarning) { - out.println("[WARNING]" + output) + out.println("[WARNING]" + output); } else { out.println("[INFO] " + output); diff --git a/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java b/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java index e155bc26c48..c9cb6625947 100644 --- a/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java +++ b/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java @@ -439,14 +439,6 @@ static String moveUp(int n) { return "\u001B[" + n + "F"; } - static String overlined() { - return "\u001B[53m"; - } - - static String underlined() { - return "\u001B[4m"; - } - public static String printCursorPosition() { return "\u001B[6n"; } @@ -458,11 +450,7 @@ public static String noBackground() { public static String normal() { return "\u001B[0m"; } - - public static String lightBackground() { - return "\u001B[48;5;250m"; - } - + static String moveDown(int n) { return "\u001B[" + n + "E"; } From 1ed364336451a7952cf6b7dd57bbdf55f63332d8 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 27 Jun 2024 15:52:27 +0200 Subject: [PATCH 11/66] improved message printing --- src/org/rascalmpl/library/Messages.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index 388edc3b7aa..f830339b915 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -102,16 +102,17 @@ public static void write(IList messages, PrintWriter out) { + ((IString) msg.get("msg")).getValue(); if (isError) { - out.println("[ERROR] " + output); + out.println("[ERROR] " + output); } else if (isWarning) { - out.println("[WARNING]" + output); + out.println("[WARNING] " + output); } else { - out.println("[INFO] " + output); + out.println("[INFO] " + output); } } + out.flush(); return; } } From b83b6f3eeb87cb826814547f65113ee74817d42e Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 27 Jun 2024 15:55:00 +0200 Subject: [PATCH 12/66] improved message printing --- src/org/rascalmpl/interpreter/utils/RascalManifest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/rascalmpl/interpreter/utils/RascalManifest.java b/src/org/rascalmpl/interpreter/utils/RascalManifest.java index da498a568f9..6ae92c5a325 100644 --- a/src/org/rascalmpl/interpreter/utils/RascalManifest.java +++ b/src/org/rascalmpl/interpreter/utils/RascalManifest.java @@ -76,7 +76,7 @@ public String getManifestVersionNumber(ISourceLocation project) throws IOExcepti } } - return "Unknown version for " + project + " (missing MANIFEST.MF or Specification-Version in MANIFEST.MF)"; + return "unknown"; } public Manifest getDefaultManifest(String projectName) { From 66fd82be7914178bcfbf5354ba7b557989e37608 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 27 Jun 2024 20:21:27 +0200 Subject: [PATCH 13/66] improved configuration checking code --- .../interpreter/utils/RascalManifest.java | 16 +++++++- src/org/rascalmpl/library/Messages.java | 13 +++++- .../rascalmpl/library/util/PathConfig.java | 40 ++++++++++++------- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/org/rascalmpl/interpreter/utils/RascalManifest.java b/src/org/rascalmpl/interpreter/utils/RascalManifest.java index 6ae92c5a325..71469b6e48a 100644 --- a/src/org/rascalmpl/interpreter/utils/RascalManifest.java +++ b/src/org/rascalmpl/interpreter/utils/RascalManifest.java @@ -39,6 +39,7 @@ public class RascalManifest { protected static final String SOURCE = "Source"; protected static final String META_INF = "META-INF"; public static final String META_INF_RASCAL_MF = META_INF + "/RASCAL.MF"; + public static final String META_INF_MANIFEST_MF = META_INF + "/MANIFEST.MF"; protected static final String MAIN_MODULE = "Main-Module"; protected static final String MAIN_FUNCTION = "Main-Function"; protected static final String PROJECT_NAME = "Project-Name"; @@ -59,14 +60,17 @@ public static String getRascalVersionNumber() { } } - return "Rascal version not specified in META-INF/MANIFEST.MF???"; + return "Not specified"; } catch (IOException e) { return "unknown (due to " + e.getMessage(); } } + /** + * This looks into the META-INF/MANIFEST.MF file for a Name and Specification-Version + */ public String getManifestVersionNumber(ISourceLocation project) throws IOException { - Manifest mf = new Manifest(manifest(project)); + Manifest mf = new Manifest(javaManifest(project)); String bundleName = mf.getMainAttributes().getValue("Name"); if (bundleName != null && bundleName.equals("rascal")) { @@ -274,6 +278,14 @@ public InputStream manifest(ISourceLocation root) { } } + public InputStream javaManifest(ISourceLocation root) { + try { + return URIResolverRegistry.getInstance().getInputStream(URIUtil.getChildLocation(JarURIResolver.jarify(root), META_INF_MANIFEST_MF)); + } catch (IOException e) { + return null; + } + } + public String getProjectName(ISourceLocation root) { return getManifestProjectName(manifest(root)); } diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index f830339b915..1746841bade 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -52,7 +52,6 @@ public static IValue error(String message, ISourceLocation loc) { public static void write(IList messages, PrintWriter out) { int maxLine = 0; int maxColumn = 0; - boolean hasErrors = false; for (IValue error : messages) { ISourceLocation loc = (ISourceLocation) ((IConstructor) error).get("at"); @@ -71,6 +70,18 @@ public static void write(IList messages, PrintWriter out) { ISourceLocation l1 = (ISourceLocation) m1.get("at"); ISourceLocation l2 = (ISourceLocation) m2.get("at"); + if (!l1.getScheme().equals(l2.getScheme())) { + return l1.getScheme().compareTo(l2.getScheme()); + } + + if (!l1.getAuthority().equals(l2.getAuthority())) { + return l1.getAuthority().compareTo(l2.getAuthority()); + } + + if (!l1.getPath().equals(l2.getPath())) { + return l1.getPath().compareTo(l2.getPath()); + } + if (l1.getBeginLine() == l2.getBeginLine()) { return Integer.compare(l1.getBeginColumn(), l2.getBeginColumn()); } diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 987f056fbf2..5a7ad7a5c25 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -20,6 +20,7 @@ import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; import org.rascalmpl.uri.file.MavenRepositoryURIResolver; +import org.rascalmpl.uri.project.ProjectURIResolver; import org.rascalmpl.values.IRascalValueFactory; import org.rascalmpl.values.ValueFactoryFactory; @@ -510,22 +511,31 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes // always add the standard library but not for the project named "rascal" // which contains the (source of) the standard library, and if we already // have a dependency on the rascal project we don't add it here either. - libsWriter.append(resolveCurrentRascalRuntimeJar()); + var rascalLib = resolveCurrentRascalRuntimeJar(); + messages.append(Messages.info("Effective rascal library", rascalLib)); + libsWriter.append(rascalLib); } - else { - if (mode == RascalConfigMode.INTERPRETER) { - // the Rascal interpreter can not escape its own classpath, whether - // or not we configure a different version in the current project's - // pom.xml - RascalManifest rmf = new RascalManifest(); - var builtinRascalProject = reg.logicalToPhysical(resolveCurrentRascalRuntimeJar()); - var builtinVersion = rmf.getManifestVersionNumber(builtinRascalProject); - var dependentRascalProject = reg.logicalToPhysical(rascalProject); - var dependentVersion = rmf.getManifestVersionNumber(dependentRascalProject); - - if (!builtinVersion.equals(dependentVersion)) { - messages.append(Messages.warning("Dependency on Rascal is " + dependentVersion + " while " + builtinVersion + " is effective.", getPomXmlLocation(manifestRoot))); - } + else if (projectName.equals("rascal")) { + messages.append(Messages.info("detected rascal self-application", URIUtil.correctLocation("project", projectName, "pom.xml"))); + } + else if (rascalProject != null) { + // The Rascal interpreter can not escape its own classpath, whether + // or not we configure a different version in the current project's + // pom.xml or not. So that pom dependency is always ignored! + + // We check this also in COMPILED mode, for the sake of consistency, + // but it is not strictly necessary since the compiler can check and compile + // against any standard library on the libs path, even if it's running + // itself against a different rascal runtime and standard library. + + RascalManifest rmf = new RascalManifest(); + var builtinVersion = RascalManifest.getRascalVersionNumber(); + var dependentRascalProject = reg.logicalToPhysical(rascalProject); + var dependentVersion = rmf.getManifestVersionNumber(dependentRascalProject); + + if (!builtinVersion.equals(dependentVersion)) { + messages.append(Messages.info("Effective version: " + builtinVersion, resolveCurrentRascalRuntimeJar())); + messages.append(Messages.warning("Unused rascal dependency: " + dependentVersion, getPomXmlLocation(manifestRoot))); } } From 107f68792917793849a127d8e8c789a22fd786d6 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 27 Jun 2024 20:42:08 +0200 Subject: [PATCH 14/66] improved error messages --- src/org/rascalmpl/library/Messages.java | 21 +++++++++++++++---- .../rascalmpl/library/util/PathConfig.java | 6 +++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index 1746841bade..253c40da8c7 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -82,12 +82,25 @@ public static void write(IList messages, PrintWriter out) { return l1.getPath().compareTo(l2.getPath()); } - if (l1.getBeginLine() == l2.getBeginLine()) { - return Integer.compare(l1.getBeginColumn(), l2.getBeginColumn()); + if (l1.hasLineColumn() && l2.hasLineColumn()) { + if (l1.getBeginLine() == l2.getBeginLine()) { + return Integer.compare(l1.getBeginColumn(), l2.getBeginColumn()); + } + else { + return Integer.compare(l1.getBeginLine(), l2.getBeginLine()); + } } - else { - return Integer.compare(l1.getBeginLine(), l2.getBeginLine()); + else if (l1.hasOffsetLength() && l2.hasOffsetLength()) { + return Integer.compare(l1.getOffset(), l2.getOffset()); } + else if (l1.hasOffsetLength()) { + return -1; + } + else if (l2.hasOffsetLength()) { + return 1; + } + + return 0; }); for (IConstructor msg : sortedStream.collect(Collectors.toList())) { diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 5a7ad7a5c25..5787b6a43e1 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -512,11 +512,11 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes // which contains the (source of) the standard library, and if we already // have a dependency on the rascal project we don't add it here either. var rascalLib = resolveCurrentRascalRuntimeJar(); - messages.append(Messages.info("Effective rascal library", rascalLib)); + messages.append(Messages.info("Effective rascal library: " + rascalLib, getPomXmlLocation(manifestRoot))); libsWriter.append(rascalLib); } else if (projectName.equals("rascal")) { - messages.append(Messages.info("detected rascal self-application", URIUtil.correctLocation("project", projectName, "pom.xml"))); + messages.append(Messages.info("detected rascal self-application", getPomXmlLocation(manifestRoot))); } else if (rascalProject != null) { // The Rascal interpreter can not escape its own classpath, whether @@ -534,7 +534,7 @@ else if (rascalProject != null) { var dependentVersion = rmf.getManifestVersionNumber(dependentRascalProject); if (!builtinVersion.equals(dependentVersion)) { - messages.append(Messages.info("Effective version: " + builtinVersion, resolveCurrentRascalRuntimeJar())); + messages.append(Messages.info("Effective rascal version: " + builtinVersion, getPomXmlLocation(manifestRoot))); messages.append(Messages.warning("Unused rascal dependency: " + dependentVersion, getPomXmlLocation(manifestRoot))); } } From 63ea0331f98923d4a25759dd4697ac17809914c7 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 28 Jun 2024 11:21:33 +0200 Subject: [PATCH 15/66] finetuning interpreter mode wrt std library linkage --- .../rascalmpl/library/util/PathConfig.java | 78 ++++++++++++++----- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 5787b6a43e1..eeda6611a25 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -398,9 +398,11 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { return current; } /** - * This will create a PathConfig by learning from the `MANIFEST/RASCAL.MF` file where the sources + * This will create a PathConfig instance by learning from the `MANIFEST/RASCAL.MF` file where the sources * are, and from `pom.xml` which libraries to reference. If this PathConfig is - * for the interpreter it adds more folders to the source path than if its for the compiler. In the future + * for the interpreter it adds more folders to the source path than if its for the compiler. + * + * In the future * we'd like the source folders also configured by the pom.xml but for now we read it from RASCAL.MF for * the sake of efficiency (reading pom.xml requires an XML parse and DOM traversal.) Also we need * some level of backward compatibility until everybody has moved to using pom.xml. @@ -410,6 +412,20 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { * those projects are added to the configuration instead of the jar files. * For compiler configs this works differently than for interpreter configs. * The latter adds source folders to the `srcs` while the former adds target folders to the `libs`. + * + * If the current project is the rascal project itself, then precautions are taken to avoid double + * entries in libs and srcs, always promoting the current project over the released rascal version. + * + * If the current project depends on a rascal project (e.g. for compiling Java code against Rascal's + * and vallang's run-time classes), then this dependency is ignored and the current JVM's rascal version + * is used instead. The literal jar file is put in the pathConfig for transparancy's sake, and a + * warning is added to the `messages` list. + * + * This code also checks for existence of the actual jar files and source folders that are depended on. + * If the files or folders do not exist, an an error is added to the messages field. + * + * Clients of this method must promote the messages list to a UI facing log, such as the diagnostics + * or problems view in an IDE, an error LOG for a CI and stderr or stdout for console applications. * * @param manifest the source location of the folder which contains MANIFEST/RASCAL.MF. * @param RascalConfigMode.INTERPRETER | RascalConfigMode.COMPILER @@ -448,10 +464,14 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes IList mavenClasspath = getPomXmlCompilerClasspath(manifestRoot); // This processes Rascal libraries we can find in maven dependencies, - // adding them to libs or srcs depending on which mode we are in. - // also if a current project is open with the same name, we defer to its - // srcs or target folder instead, for easy development of cross-project - // features in the IDE. + // adding them to libs or srcs depending on which mode we are in; interpreted or compiled. + // + // * If a current project is open with the same name, we defer to its + // srcs (interpreter mode only) and target folder (both modes) instead, + // for easy development of cross-project features in the IDE. + // * Only the rascal project itself is never used from source project, to avoid + // complex bootstrapping situations. + for (IValue elem : mavenClasspath) { ISourceLocation dep = (ISourceLocation) elem; String libProjectName = manifest.getManifestProjectName(manifest.manifest(dep)); @@ -462,7 +482,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes } if (libProjectName != null) { - if (reg.exists(projectLoc)) { + if (reg.exists(projectLoc) && dep != rascalProject) { // The project we depend on is available in the current workspace. // so we configure for using the current state of that project. PathConfig childConfig = fromSourceProjectRascalManifest(projectLoc, mode); @@ -487,16 +507,18 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes if (!reg.exists(dep)) { messages.append(Messages.error("Declared dependency does not exist: " + dep, getPomXmlLocation(manifestRoot))); } - - switch (mode) { - case COMPILER: - libsWriter.append(dep); - break; - case INTERPRETER: - addLibraryToSourcePath(manifest, reg, srcsWriter, dep); - break; - default: - messages.append(Messages.error("Can not recognize configuration mode (should be COMPILER or INTERPRETER):" + mode, getRascalMfLocation(manifestRoot))); + else { + switch (mode) { + case COMPILER: + libsWriter.append(dep); + break; + case INTERPRETER: + libsWriter.append(dep); + addLibraryToSourcePath(reg, srcsWriter, messages, dep); + break; + default: + messages.append(Messages.error("Can not recognize configuration mode (should be COMPILER or INTERPRETER):" + mode, getRascalMfLocation(manifestRoot))); + } } } } @@ -551,6 +573,7 @@ else if (rascalProject != null) { messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); } + for (String srcName : manifest.getSourceRoots(manifestRoot)) { var srcFolder = URIUtil.getChildLocation(manifestRoot, srcName); @@ -570,15 +593,32 @@ else if (rascalProject != null) { messages.done()); } - private static void addLibraryToSourcePath(RascalManifest manifest, URIResolverRegistry reg, IListWriter srcsWriter, - ISourceLocation jar) { + private static void addLibraryToSourcePath(URIResolverRegistry reg, IListWriter srcsWriter, IListWriter messages, ISourceLocation jar) { + if (!reg.exists(URIUtil.getChildLocation(jar, RascalManifest.META_INF_RASCAL_MF))) { + // skip all the non Rascal libraries + return; + } + + + var manifest = new RascalManifest(); + + // the rascal dependency leads to a dependency on the std:/// location, somewhere _inside_ of the rascal jar + if (manifest.getProjectName(jar).equals("rascal")) { + srcsWriter.append(URIUtil.rootLocation("std")); + return; + } + boolean foundSrc = false; + for (String src : manifest.getSourceRoots(jar)) { ISourceLocation srcLib = URIUtil.getChildLocation(jar, src); if (reg.exists(srcLib)) { srcsWriter.append(srcLib); foundSrc = true; } + else { + messages.append(Messages.error(srcLib + " source folder does not exist.", URIUtil.getChildLocation(jar, RascalManifest.META_INF_RASCAL_MF))); + } } if (!foundSrc) { From f767142c41704c8a187c084e0ba0c6a0c61559a5 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 28 Jun 2024 11:22:45 +0200 Subject: [PATCH 16/66] changed warning message --- src/org/rascalmpl/library/util/PathConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index eeda6611a25..fd6d13f9b05 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -557,7 +557,7 @@ else if (rascalProject != null) { if (!builtinVersion.equals(dependentVersion)) { messages.append(Messages.info("Effective rascal version: " + builtinVersion, getPomXmlLocation(manifestRoot))); - messages.append(Messages.warning("Unused rascal dependency: " + dependentVersion, getPomXmlLocation(manifestRoot))); + messages.append(Messages.warning("Different rascal dependency is not used: " + dependentVersion, getPomXmlLocation(manifestRoot))); } } From 38bdf96c40db164e21bbc58b0c12f09bcfc0445a Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 28 Jun 2024 13:22:33 +0200 Subject: [PATCH 17/66] The std scheme is not opaque anymore but transparant ``` rascal>resolveLocation(|std:///|) loc: |jar+file:///Users/jurgenv/git/rascal/target/rascal-0.40.3-RC2-SNAPSHOT.jar!/org/rascalmpl/library/| ``` --- .../rascalmpl/library/util/PathConfig.java | 6 +-- .../uri/StandardLibraryURIResolver.java | 49 +++++++++++++++++-- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index fd6d13f9b05..97b49c4a2cc 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -398,7 +398,7 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { return current; } /** - * This will create a PathConfig instance by learning from the `MANIFEST/RASCAL.MF` file where the sources + * This creates a PathConfig instance by learning from the `MANIFEST/RASCAL.MF` file where the sources * are, and from `pom.xml` which libraries to reference. If this PathConfig is * for the interpreter it adds more folders to the source path than if its for the compiler. * @@ -429,7 +429,7 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { * * @param manifest the source location of the folder which contains MANIFEST/RASCAL.MF. * @param RascalConfigMode.INTERPRETER | RascalConfigMode.COMPILER - * @return a PathConfig instance, fully informed to start initializing a Rascal compiler or interpreter. + * @return a PathConfig instance, fully informed to start initializing a Rascal compiler or interpreter, and including a list of revelant info, warning and error messages. * @throws nothing, because all errors are collected in a messages field of the PathConfig. */ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifestRoot, RascalConfigMode mode) { @@ -448,7 +448,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes libsWriter.append(resolveCurrentRascalRuntimeJar()); } catch (IOException e) { - + messages.append(Messages.error(e.getMessage(), manifestRoot)); } } diff --git a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java index dd748e4a3fc..4b523044653 100644 --- a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java +++ b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java @@ -1,11 +1,52 @@ package org.rascalmpl.uri; -import org.rascalmpl.uri.libraries.ClassResourceInput; +import java.io.IOException; -public class StandardLibraryURIResolver extends ClassResourceInput { +import org.rascalmpl.library.util.PathConfig; +import org.rascalmpl.uri.jar.JarURIResolver; +import io.usethesource.vallang.ISourceLocation; - public StandardLibraryURIResolver() { - super("std", StandardLibraryURIResolver.class, "/org/rascalmpl/library"); +/** + * Provides transparant access to the source code of the one and only standard library + * that should be on the source path of the interpreter, which is contained in the same + * jar as the current interpreter is from. + * + * The std:/// scheme is mainly used by the interpreter, but it is also the location + * of distributed sources of the standard library for use in the debugger. The references + * that the type-checker produces for UI feature in the IDE also depend on this scheme. + */ +public class StandardLibraryURIResolver implements ILogicalSourceLocationResolver { + private static final ISourceLocation currentRascalJar = + URIUtil.getChildLocation( + JarURIResolver.jarify( + resolveCurrentRascalJar() + ), + "org/rascalmpl/library" + ); + + private static ISourceLocation resolveCurrentRascalJar() { + try { + return PathConfig.resolveCurrentRascalRuntimeJar(); + } + catch (IOException e) { + // this will be reported elsewhere in PathConfi - + return null; + } + } + + @Override + public ISourceLocation resolve(ISourceLocation input) throws IOException { + return URIUtil.getChildLocation(currentRascalJar, input.getPath()); + } + + @Override + public String scheme() { + return "std"; + } + + @Override + public String authority() { + return ""; } } From a14a82a91d059e08bb4add815d57f529d3e17b8d Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 28 Jun 2024 13:27:44 +0200 Subject: [PATCH 18/66] added more comments --- src/org/rascalmpl/uri/StandardLibraryURIResolver.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java index 4b523044653..cf8494cc8a2 100644 --- a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java +++ b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java @@ -11,9 +11,17 @@ * that should be on the source path of the interpreter, which is contained in the same * jar as the current interpreter is from. * - * The std:/// scheme is mainly used by the interpreter, but it is also the location + * The std:/// scheme is mainly used by the interpreter, to load library modules; but it is also the location * of distributed sources of the standard library for use in the debugger. The references * that the type-checker produces for UI feature in the IDE also depend on this scheme. + * + * This is accomplished by: + * 1. rewriting all the references to the source locations of the library in + * project://rascal/src/org/rascalmpl/library/...` to `std:///...`. This is done by the "packager" + * 2. copying all the .rsc files of the library to the jar in the right location (mvn resources plugin) + * 3. resolving std:/// to the same location inside of the jar + * 4. **not** having more than one standard library in the classpath of the JVM, or more than one + * standard library in the libs path of a PathConfig. */ public class StandardLibraryURIResolver implements ILogicalSourceLocationResolver { private static final ISourceLocation currentRascalJar = From d076cf00365c38b65b88478be8e300545fd382f3 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sat, 14 Sep 2024 15:47:47 +0200 Subject: [PATCH 19/66] fixed false positive project name error if the project:// scheme is used --- src/org/rascalmpl/library/util/PathConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 97b49c4a2cc..fda1ccc3d28 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -561,7 +561,9 @@ else if (rascalProject != null) { } } - if (!projectName.equals(URIUtil.getLocationName(manifestRoot))) { + ISourceLocation projectLoc = URIUtil.correctLocation("project", projectName, ""); + + if (!projectLoc.equals(manifestRoot) && !projectName.equals(URIUtil.getLocationName(manifestRoot))) { messages.append(Messages.error("Project-Name in RASCAL.MF (" + projectName + ") should be equal to folder name (" + URIUtil.getLocationName(manifestRoot) + ")", getRascalMfLocation(manifestRoot))); } From 5ea2006c0d79b68562561dcc1d2c57dbe6076aaa Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 16 Sep 2024 10:20:44 +0200 Subject: [PATCH 20/66] removed unused import --- src/org/rascalmpl/library/util/PathConfig.java | 1 - src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index fda1ccc3d28..0d610cdf5b7 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -20,7 +20,6 @@ import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; import org.rascalmpl.uri.file.MavenRepositoryURIResolver; -import org.rascalmpl.uri.project.ProjectURIResolver; import org.rascalmpl.values.IRascalValueFactory; import org.rascalmpl.values.ValueFactoryFactory; diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java index b2c3f94d953..5af8f2200c1 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java @@ -128,6 +128,7 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio } public static ISourceLocation inferProjectRoot(Class clazz) { + try { String file = clazz.getProtectionDomain().getCodeSource().getLocation().getPath(); if (file.endsWith(".jar")) { From ac8080fcc81b55e1947a8dd17401a957715e1782 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 16 Sep 2024 12:50:17 +0200 Subject: [PATCH 21/66] fixed issue in std:// resolver in the case where we are applying it while testing from rascal/target/classes instead of from a jar file. now the tests can succeed as well --- src/org/rascalmpl/library/util/PathConfig.java | 5 +++-- src/org/rascalmpl/uri/StandardLibraryURIResolver.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 0d610cdf5b7..825dbae5f14 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -354,14 +354,15 @@ public static ISourceLocation resolveDependencyFromResourcesOnCurrentClasspath(S // parser to make sense of it and then convert it to an ISourceLocation loc = vf.sourceLocation("file", null, URIUtil.fromURL(new URL(url.getPath())).getPath()); + // unjarify the path + loc = URIUtil.changePath(loc, loc.getPath().replace("!/" + RascalManifest.META_INF_RASCAL_MF, "")); } else { // this is typically a target folder loc = vf.sourceLocation(URIUtil.fromURL(url)); + loc = URIUtil.getParentLocation(URIUtil.getParentLocation(loc)); } - // unjarify the path - loc = URIUtil.changePath(loc, loc.getPath().replace("!/" + RascalManifest.META_INF_RASCAL_MF, "")); return loc; } diff --git a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java index cf8494cc8a2..d6e3d824557 100644 --- a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java +++ b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java @@ -37,7 +37,7 @@ private static ISourceLocation resolveCurrentRascalJar() { return PathConfig.resolveCurrentRascalRuntimeJar(); } catch (IOException e) { - // this will be reported elsewhere in PathConfi - + // this will be reported elsewhere in PathConfig.messages - return null; } } From 11739c490e6e3c102105445c4c4cebd4f59ee75a Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 16 Sep 2024 13:03:34 +0200 Subject: [PATCH 22/66] added proper warning for conflicting rascal-lsp instances on the classpath --- .../rascalmpl/library/util/PathConfig.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 825dbae5f14..0e4f15d9201 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.net.URISyntaxException; @@ -15,6 +16,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.jar.Manifest; + import org.rascalmpl.interpreter.utils.RascalManifest; import org.rascalmpl.library.Messages; import org.rascalmpl.uri.URIResolverRegistry; @@ -481,6 +484,28 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes rascalProject = dep; } + // Rascal LSP is special because the VScode extension pre-loads it into the parametric DSL VM. + // If the version is different, then the debugger may point to the wrong code, and also the Rascal + // IDE features like "jump-to-definition" could be off. + if (libProjectName.equals("rascal-lsp")) { + try { + var loadedRascalLsp = resolveDependencyFromResourcesOnCurrentClasspath("rascal-lsp"); + + try (InputStream in = reg.getInputStream(loadedRascalLsp), InputStream in2 = reg.getInputStream(dep)) { + var version = new Manifest(in).getMainAttributes().getValue("Specification-Version"); + var otherVersion = new Manifest(in2).getfMainAttributes().getValue("Specification-Version"); + + if (version.equals(otherVersion)) { + messages.append(Messages.warning("Pom.xml dependency on rascal-lsp has version " + otherVersion + " while the effective version in the VScode extension is " + version + ". This can have funny effects in the IDE while debugging or code browsing.", getPomXmlLocation(manifestRoot))); + } + } + } + catch (FileNotFoundException e) { + // this is ok. there is not a duplicate presence of rascal-lsp. + } + + } + if (libProjectName != null) { if (reg.exists(projectLoc) && dep != rascalProject) { // The project we depend on is available in the current workspace. From cb4b38e3ff3aa421c687b943650a60211ee82917 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 16 Sep 2024 13:05:45 +0200 Subject: [PATCH 23/66] fixed typo --- src/org/rascalmpl/library/util/PathConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 0e4f15d9201..5dcb99ec852 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -491,9 +491,9 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes try { var loadedRascalLsp = resolveDependencyFromResourcesOnCurrentClasspath("rascal-lsp"); - try (InputStream in = reg.getInputStream(loadedRascalLsp), InputStream in2 = reg.getInputStream(dep)) { + try (InputStream in = reg.getInputStream(loadedRascalLsp); InputStream in2 = reg.getInputStream(dep)) { var version = new Manifest(in).getMainAttributes().getValue("Specification-Version"); - var otherVersion = new Manifest(in2).getfMainAttributes().getValue("Specification-Version"); + var otherVersion = new Manifest(in2).getMainAttributes().getValue("Specification-Version"); if (version.equals(otherVersion)) { messages.append(Messages.warning("Pom.xml dependency on rascal-lsp has version " + otherVersion + " while the effective version in the VScode extension is " + version + ". This can have funny effects in the IDE while debugging or code browsing.", getPomXmlLocation(manifestRoot))); From 45978002046a7b1e983738b628ac9d9f530f2f1b Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 16 Sep 2024 14:05:03 +0200 Subject: [PATCH 24/66] removed legacy usages of javaCompilerPath --- src/org/rascalmpl/library/lang/java/m3/AST.rsc | 2 +- src/org/rascalmpl/library/lang/java/m3/Core.rsc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/rascalmpl/library/lang/java/m3/AST.rsc b/src/org/rascalmpl/library/lang/java/m3/AST.rsc index c427c772edf..d1f362b666e 100644 --- a/src/org/rascalmpl/library/lang/java/m3/AST.rsc +++ b/src/org/rascalmpl/library/lang/java/m3/AST.rsc @@ -414,7 +414,7 @@ public set[Declaration] createAstsFromMavenProject(loc project, bool collectBind throw " is not a valid directory"; } - classPaths = getProjectPathConfig(project).javaCompilerPath; + classPaths = getProjectPathConfig(project).libs; sourcePaths = getPaths(project, "java"); return createAstsFromFiles({ p | sp <- sourcePaths, p <- find(sp, "java"), isFile(p)}, collectBindings, sourcePath = [*findRoots(sourcePaths)], classPath = classPaths, errorRecovery = errorRecovery, javaVersion = javaVersion); } diff --git a/src/org/rascalmpl/library/lang/java/m3/Core.rsc b/src/org/rascalmpl/library/lang/java/m3/Core.rsc index 634ced10f28..b79ee0755a2 100644 --- a/src/org/rascalmpl/library/lang/java/m3/Core.rsc +++ b/src/org/rascalmpl/library/lang/java/m3/Core.rsc @@ -264,7 +264,7 @@ M3 createM3FromMavenProject(loc project, bool errorRecovery = false, bool includ throw " is not a valid directory"; } - list[loc] classPaths = getProjectPathConfig(project).javaCompilerPath; + list[loc] classPaths = getProjectPathConfig(project).libs; sourcePaths = getPaths(project, "java"); M3 result = composeJavaM3(project, createM3sFromFiles({p | sp <- sourcePaths, p <- find(sp, "java"), isFile(p)}, errorRecovery = errorRecovery, sourcePath = [*findRoots(sourcePaths)], classPath = classPaths, javaVersion = javaVersion)); From 561ce9e540fb323ea5715875a68dbad4cd5a2e25 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 09:54:43 +0200 Subject: [PATCH 25/66] removed remnants of Require-Libraries --- .../interpreter/utils/RascalManifest.java | 41 +------------------ src/org/rascalmpl/library/util/Reflective.rsc | 4 -- 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/src/org/rascalmpl/interpreter/utils/RascalManifest.java b/src/org/rascalmpl/interpreter/utils/RascalManifest.java index 71469b6e48a..447bc72aba5 100644 --- a/src/org/rascalmpl/interpreter/utils/RascalManifest.java +++ b/src/org/rascalmpl/interpreter/utils/RascalManifest.java @@ -43,9 +43,7 @@ public class RascalManifest { protected static final String MAIN_MODULE = "Main-Module"; protected static final String MAIN_FUNCTION = "Main-Function"; protected static final String PROJECT_NAME = "Project-Name"; - protected static final String REQUIRE_BUNDLES = "Require-Bundles"; - protected static final String REQUIRE_LIBRARIES = "Require-Libraries"; - + public static String getRascalVersionNumber() { try { Enumeration resources = RascalManifest.class.getClassLoader().getResources("META-INF/MANIFEST.MF"); @@ -91,7 +89,6 @@ public Manifest getDefaultManifest(String projectName) { mainAttributes.put(new Attributes.Name(MAIN_MODULE), DEFAULT_MAIN_MODULE); mainAttributes.put(new Attributes.Name(MAIN_FUNCTION), DEFAULT_MAIN_FUNCTION); mainAttributes.put(new Attributes.Name(PROJECT_NAME), projectName); - mainAttributes.put(new Attributes.Name(REQUIRE_LIBRARIES), ""); return manifest; } @@ -168,13 +165,6 @@ public String getProjectName(File jarFile) { return getManifestProjectName(manifest(jarFile)); } - /** - * @return a list of bundle names this jar depends on, or 'null' if none is configured. - */ - public List getRequiredLibraries(JarInputStream jarStream) { - return getManifestRequiredLibraries(manifest(jarStream)); - } - /** * @return the name of the main module of a deployment unit, or 'null' if none is configured. */ @@ -211,20 +201,6 @@ public boolean hasMainModule(Class clazz) { return getManifestMainModule(manifest(clazz)) != null; } - /** - * @return a list of bundle names this jar depends on, or 'null' if none is configured. - */ - public List getRequiredLibraries(File jarFile) { - return getManifestRequiredLibraries(manifest(jarFile)); - } - - /** - * @return a list of bundle names this jar depends on, or 'null' if none is configured. - */ - public List getRequiredLibraries(Class clazz) { - return getManifestRequiredLibraries(manifest(clazz)); - } - /** * @return a list of paths relative to the root of the jar, if no such option is configured * it will return ["src"]. @@ -254,17 +230,6 @@ public String getManifestMainModule(InputStream project) { public String getManifestMainFunction(InputStream project) { return getManifestAttribute(project, MAIN_FUNCTION, null); } - - /** - * @return a list of bundle names this jar depends on, or 'null' if none is configured. - */ - public List getManifestRequiredLibraries(InputStream project) { - return getManifestAttributeList(project, REQUIRE_LIBRARIES, null); - } - - public List getManifestRequiredLibraries(ISourceLocation root) { - return getManifestAttributeList(manifest(root), REQUIRE_LIBRARIES, null); - } public InputStream manifest(Class clazz) { return clazz.getResourceAsStream("/" + META_INF_RASCAL_MF); @@ -294,10 +259,6 @@ public List getSourceRoots(ISourceLocation root) { return getManifestSourceRoots(manifest(root)); } - public List getRequiredLibraries(ISourceLocation root) { - return getManifestRequiredLibraries(manifest(root)); - } - public InputStream manifest(JarInputStream stream) { JarEntry next = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); diff --git a/src/org/rascalmpl/library/util/Reflective.rsc b/src/org/rascalmpl/library/util/Reflective.rsc index 0519752c607..843b5ebebf2 100644 --- a/src/org/rascalmpl/library/util/Reflective.rsc +++ b/src/org/rascalmpl/library/util/Reflective.rsc @@ -110,9 +110,6 @@ PathConfig applyManifests(PathConfig cfg) { cfg.libs = [*expandlibs(p) | p <- cfg.libs]; cfg.bin = expandBin(cfg.bin); - // TODO: here we add features for Require-Libs by searching in a repository of installed - // jars. This has to be resolved recursively. - return cfg; } @@ -397,7 +394,6 @@ private str rascalMF(str name) = "Manifest-Version: 0.0.1 'Project-Name: 'Source: src/main/rascal - 'Require-Libraries: "; private str pomXml(str name, str group, str version) From e9fdfe07e8f7e19ace314f911a60953f05d3a843 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 11:12:04 +0200 Subject: [PATCH 26/66] check for left-over Require-Libraries warning fixed --- src/org/rascalmpl/library/util/PathConfig.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 5dcb99ec852..b70af1c8c12 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -592,8 +592,10 @@ else if (rascalProject != null) { messages.append(Messages.error("Project-Name in RASCAL.MF (" + projectName + ") should be equal to folder name (" + URIUtil.getLocationName(manifestRoot) + ")", getRascalMfLocation(manifestRoot))); } - if (!manifest.getRequiredLibraries(manifestRoot).isEmpty()) { - messages.append(Messages.info("Required-Libraries in RASCAL.MF are not used anymore. Please use Maven dependencies in pom.xml.", getRascalMfLocation(manifestRoot))); + try (InputStream mfi = manifest.manifest(manifestRoot)) { + if (!new Manifest(mfi).getMainAttributes().getValue("Require-Libraries").isEmpty()) { + messages.append(Messages.info("Require-Libraries in RASCAL.MF are not used anymore. Please use Maven dependencies in pom.xml.", getRascalMfLocation(manifestRoot))); + } } } catch (IOException e) { From 4221cb0dda746941298604526a004442aeb43994 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 17:10:38 +0200 Subject: [PATCH 27/66] optimization for the case where the m2 folder is not in the home directory --- .../uri/file/MavenRepositoryURIResolver.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 2c762b32bcd..583d49b10c7 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -79,6 +79,8 @@ * idea; but there is currently no way to register read-only logical schemes. */ public class MavenRepositoryURIResolver extends AliasedFileResolver { + private static String localRepoLocationCache; + private final Pattern authorityRegEx = Pattern.compile("^([a-zA-Z0-9-_.]+?)[!]([a-zA-Z0-9-_.]+)([!][a-zA-Z0-9\\-_.]+)$"); // groupId ! artifactId ! optionAlComplexVersionString @@ -113,7 +115,7 @@ private static String inferMavenRepositoryLocation() { // note that since it does not exist this will make all downstream resolutions fail // to "file does not exist" } - + return m2HomeFolder; } @@ -132,9 +134,14 @@ private static String computeMavenCommandName() { /** * This (slow) code runs only if the ~/.m2 folder does not exist and nobody -D'ed its location either. * That is not necessarily how mvn prioritizes its configuration steps, but it is the way we can - * get a quick enough answer most of the time. + * get a quick enough answer most of the time. It caches its result to make sure repeated calls + * to here are faster than the first. */ private static String getLocalRepositoryLocationFromMavenCommand() { + if (localRepoLocationCache != null) { + return localRepoLocationCache; + } + try { ProcessBuilder processBuilder = new ProcessBuilder(computeMavenCommandName(), "-q", @@ -150,7 +157,7 @@ private static String getLocalRepositoryLocationFromMavenCommand() { } try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - return reader.lines().collect(Collectors.joining()).trim(); + return (localRepoLocationCache = reader.lines().collect(Collectors.joining()).trim()); } } catch (IOException | InterruptedException e) { @@ -159,7 +166,6 @@ private static String getLocalRepositoryLocationFromMavenCommand() { } } - @Override public ISourceLocation resolve(ISourceLocation input) throws IOException { String authority = input.getAuthority(); From 88b88fb1d3889ed48d5e60442a097d9a2d0d8051 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 17:58:58 +0200 Subject: [PATCH 28/66] exposed new classpath resolution functions from PathConfig in util::Reflective for help in creating smart PathConfig instances --- .../rascalmpl/library/util/Reflective.java | 9 +++++++++ src/org/rascalmpl/library/util/Reflective.rsc | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/Reflective.java b/src/org/rascalmpl/library/util/Reflective.java index 1b4d4862b05..454b5d185d6 100644 --- a/src/org/rascalmpl/library/util/Reflective.java +++ b/src/org/rascalmpl/library/util/Reflective.java @@ -81,6 +81,15 @@ public IString getRascalVersion() { return values.string(RascalManifest.getRascalVersionNumber()); } + public ISourceLocation resolveDependencyFromResourcesOnCurrentClasspath(IString projectName) { + try { + return PathConfig.resolveDependencyFromResourcesOnCurrentClasspath(projectName.getValue()); + } + catch (IOException e) { + throw RuntimeExceptionFactory.io(e.getMessage()); + } + } + public IString getLineSeparator() { return values.string(System.lineSeparator()); } diff --git a/src/org/rascalmpl/library/util/Reflective.rsc b/src/org/rascalmpl/library/util/Reflective.rsc index 843b5ebebf2..6431c658483 100644 --- a/src/org/rascalmpl/library/util/Reflective.rsc +++ b/src/org/rascalmpl/library/util/Reflective.rsc @@ -52,6 +52,7 @@ transparantly. A PathConfig is also a log of the configuration process. * `ignores` list of directories and files to not compile or not interpret (these are typically subtracted from the `srcs` tree, or skipped when the compiler arives there.) * `bin` is the target root directory for the output of a compiler. Typically this directory would be linked into a zip or a jar or an executable file later. * `libs` is a list of binary dependency files (typically jar files or target folders) on other projects, for checking and linking purposes. +* `generatedSources` is where generated (intermediate) source code that has to be compiled further is located. * `messages` is a list of info, warning and error messages informing end-users about the quality of the configuration process. Typically missing dependencies would be reported here, and clashing versions. } data PathConfig @@ -88,7 +89,23 @@ data JavaBundleManifest list[str] \Bundle-ClassPath = [], list[str] \Import-Package = [] ); - + +@synopsis{Makes the location of a jar file explicit, based on the project name} +@description{ +The classpath of the current JVM is searched and jar files are searched that contain +META-INF/MANIFEST.MF file that match the given `projectName`. +} +@benefits{ +* The classpath is not used implicitly in this way, but rather explicitly. This helps +in making configuration issues tractable. +* The resulting `loc` value can be used to configure a ((PathConfig)) instance directly. +} +@javaClass{org.rascalmpl.library.util.Reflective} +java loc resolveDependencyFromResourcesOnCurrentClasspath(str projectName); + +@synopsis{Makes the location of the currently running rascal jar explicit.} +loc resolvedCurrentRascalJar() = resolveDependencyFromResourcesOnCurrentClasspath("rascal"); + loc metafile(loc l) = l + "META-INF/RASCAL.MF"; @synopsis{Converts a PathConfig and replaces all references to roots of projects or bundles From 27f91c0caf68d3f6f4618cbebeaf8428e5ee8457 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 18:07:20 +0200 Subject: [PATCH 29/66] turned off tutor temporarily --- pom.xml | 4 +-- .../rascalmpl/library/util/Reflective.java | 2 +- src/org/rascalmpl/library/util/Reflective.rsc | 30 ++++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 35322905497..661feb3bc04 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ package - + diff --git a/src/org/rascalmpl/library/util/Reflective.java b/src/org/rascalmpl/library/util/Reflective.java index 454b5d185d6..14a23c1ebef 100644 --- a/src/org/rascalmpl/library/util/Reflective.java +++ b/src/org/rascalmpl/library/util/Reflective.java @@ -81,7 +81,7 @@ public IString getRascalVersion() { return values.string(RascalManifest.getRascalVersionNumber()); } - public ISourceLocation resolveDependencyFromResourcesOnCurrentClasspath(IString projectName) { + public ISourceLocation resolveProjectOnClasspath(IString projectName) { try { return PathConfig.resolveDependencyFromResourcesOnCurrentClasspath(projectName.getValue()); } diff --git a/src/org/rascalmpl/library/util/Reflective.rsc b/src/org/rascalmpl/library/util/Reflective.rsc index 6431c658483..c679a681089 100644 --- a/src/org/rascalmpl/library/util/Reflective.rsc +++ b/src/org/rascalmpl/library/util/Reflective.rsc @@ -90,20 +90,22 @@ data JavaBundleManifest list[str] \Import-Package = [] ); -@synopsis{Makes the location of a jar file explicit, based on the project name} -@description{ -The classpath of the current JVM is searched and jar files are searched that contain -META-INF/MANIFEST.MF file that match the given `projectName`. -} -@benefits{ -* The classpath is not used implicitly in this way, but rather explicitly. This helps -in making configuration issues tractable. -* The resulting `loc` value can be used to configure a ((PathConfig)) instance directly. -} -@javaClass{org.rascalmpl.library.util.Reflective} -java loc resolveDependencyFromResourcesOnCurrentClasspath(str projectName); - -@synopsis{Makes the location of the currently running rascal jar explicit.} +// @synopsis{Makes the location of a jar file explicit, based on the project name} +// @description{ +// The classpath of the current JVM is searched and jar files are searched that contain +// META-INF/MANIFEST.MF file that match the given `projectName`. +// } +// @benefits{ +// * This is typically used to link bootstrap libraries such as rascal.jar and rascal-lsp.jar +// into testing ((PathConfig))s. +// * The classpath is not used implicitly in this way, but rather explicitly. This helps +// in making configuration issues tractable. +// * The resulting `loc` value can be used to configure a ((PathConfig)) instance directly. +// } +// @javaClass{org.rascalmpl.library.util.Reflective} +java loc resolveProjectOnClasspath(str projectName); + +// @synopsis{Makes the location of the currently running rascal jar explicit.} loc resolvedCurrentRascalJar() = resolveDependencyFromResourcesOnCurrentClasspath("rascal"); loc metafile(loc l) = l + "META-INF/RASCAL.MF"; From b437fbf72b987822c7f997acd737be97de925a22 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 18:31:09 +0200 Subject: [PATCH 30/66] necessary tools for rascal-lsp --- .../rascalmpl/library/util/PathConfig.java | 43 +++++++++++++++---- src/org/rascalmpl/library/util/Reflective.rsc | 2 +- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index b70af1c8c12..3e3d3fa7e21 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.StringReader; import java.io.StringWriter; import java.net.URISyntaxException; import java.net.URL; @@ -32,6 +33,9 @@ import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; +import io.usethesource.vallang.IWithKeywordParameters; +import io.usethesource.vallang.exceptions.FactTypeUseException; +import io.usethesource.vallang.io.StandardTextReader; import io.usethesource.vallang.type.Type; import io.usethesource.vallang.type.TypeFactory; import io.usethesource.vallang.type.TypeStore; @@ -144,15 +148,6 @@ public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, IS this.generatedSources = generatedSources; this.messages = convertMessages(messages); } - - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources, IList messages, ISourceLocation repo) { - this.srcs = initializeLocList(srcs); - this.libs = initializeLocList(libs); - this.bin = bin; - this.ignores = initializeLocList(ignores); - this.generatedSources = generatedSources; - this.messages = convertMessages(messages); - } private static IList messages(IConstructor pcfg) { return getListValueFromConstructor(pcfg, defaultMessages, "messages"); @@ -400,6 +395,36 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { return current; } + + public PathConfig parse(String pathConfigString) throws IOException { + try { + IConstructor cons = (IConstructor) new StandardTextReader().read(vf, store, PathConfigType, new StringReader(pathConfigString)); + IWithKeywordParameters kwp = cons.asWithKeywordParameters(); + + IList srcs = (IList) kwp.getParameter("srcs"); + IList libs = (IList) kwp.getParameter("libs"); + IList ignores = (IList) kwp.getParameter("ignores"); + ISourceLocation generated = (ISourceLocation) kwp.getParameter("generatedSources"); + IList messages = (IList) kwp.getParameter("message"); + + ISourceLocation bin = (ISourceLocation) kwp.getParameter("bin"); + + PathConfig pcfg = new PathConfig( + srcs != null ? srcs : vf.list(), + libs != null ? libs : vf.list(), + bin != null ? bin : URIUtil.rootLocation("cwd"), + ignores != null ? ignores : vf.list(), + generated != null ? generated : null, + messages != null ? messages : vf.list() + ); + + return pcfg; + } + catch (FactTypeUseException e) { + throw new IOException(e); + } + } + /** * This creates a PathConfig instance by learning from the `MANIFEST/RASCAL.MF` file where the sources * are, and from `pom.xml` which libraries to reference. If this PathConfig is diff --git a/src/org/rascalmpl/library/util/Reflective.rsc b/src/org/rascalmpl/library/util/Reflective.rsc index c679a681089..51fa8dc7e7d 100644 --- a/src/org/rascalmpl/library/util/Reflective.rsc +++ b/src/org/rascalmpl/library/util/Reflective.rsc @@ -102,7 +102,7 @@ data JavaBundleManifest // in making configuration issues tractable. // * The resulting `loc` value can be used to configure a ((PathConfig)) instance directly. // } -// @javaClass{org.rascalmpl.library.util.Reflective} +@javaClass{org.rascalmpl.library.util.Reflective} java loc resolveProjectOnClasspath(str projectName); // @synopsis{Makes the location of the currently running rascal jar explicit.} From 15968603ce8aa38c2e38aee00d6ec67dc46e9e9e Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 18:34:34 +0200 Subject: [PATCH 31/66] retrieved more utility functions required in rascal-lsp for some reason --- .../rascalmpl/library/util/PathConfig.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 3e3d3fa7e21..645d325fbb7 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.jar.Manifest; +import org.rascalmpl.interpreter.Configuration; import org.rascalmpl.interpreter.utils.RascalManifest; import org.rascalmpl.library.Messages; import org.rascalmpl.uri.URIResolverRegistry; @@ -808,6 +809,85 @@ String makeFileName(String qualifiedModuleName, String extension) { return qualifiedModuleName.replaceAll("::", "/") + "." + extension; } + public String getModuleName(ISourceLocation moduleLoc) throws IOException{ + String modulePath = moduleLoc.getPath(); + if(!modulePath.endsWith(".rsc")){ + throw new IOException("Not a Rascal source file: " + moduleLoc); + } + + if (moduleLoc.getScheme().equals("std") || moduleLoc.getScheme().equals("lib")) { + return pathToModulename(modulePath, "/"); + } + + for(ISourceLocation dir : srcs){ + if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ + return pathToModulename(modulePath, dir.getPath()); + } + } + + for (ISourceLocation dir : libs) { + if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ + return pathToModulename(modulePath, dir.getPath()); + } + } + + throw new IOException("No module name found for " + moduleLoc + "\n" + this); + + } + + private String pathToModulename(String modulePath, String folder) { + String moduleName = modulePath.replaceFirst(folder, "").replace(".rsc", ""); + if(moduleName.startsWith("/")){ + moduleName = moduleName.substring(1, moduleName.length()); + } + return moduleName.replace("/", "::"); + } + + private String moduleToDir(String module) { + return module.replaceAll(Configuration.RASCAL_MODULE_SEP, Configuration.RASCAL_PATH_SEP); + } + + private ISourceLocation getFullURI(String path, ISourceLocation dir) throws URISyntaxException { + return URIUtil.getChildLocation(dir, path); + } + + public List listModuleEntries(String moduleRoot) { + assert !moduleRoot.endsWith("::"); + final URIResolverRegistry reg = URIResolverRegistry.getInstance(); + try { + String modulePath = moduleToDir(moduleRoot); + List result = new ArrayList<>(); + for (ISourceLocation dir : srcs) { + ISourceLocation full = getFullURI(modulePath, dir); + if (reg.exists(full)) { + try { + String[] entries = reg.listEntries(full); + if (entries == null) { + continue; + } + for (String module: entries ) { + if (module.endsWith(Configuration.RASCAL_FILE_EXT)) { + result.add(module.substring(0, module.length() - Configuration.RASCAL_FILE_EXT.length())); + } + else if (module.indexOf('.') == -1 && reg.isDirectory(getFullURI(module, full))) { + // a sub folder path + result.add(module + "::"); + } + } + } + catch (IOException e) { + } + } + } + if (result.size() > 0) { + return result; + } + return null; + } catch (URISyntaxException e) { + return null; + } + } + /** * Convert PathConfig Java object to pathConfig Rascal constructor for use * in Rascal code or for serialization and printing. From e4aa0d092e9ecba5079de1ebf2d13a1d13923cec Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 18:37:10 +0200 Subject: [PATCH 32/66] used constants better --- src/org/rascalmpl/library/util/PathConfig.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 645d325fbb7..59c59716627 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -815,7 +815,7 @@ public String getModuleName(ISourceLocation moduleLoc) throws IOException{ throw new IOException("Not a Rascal source file: " + moduleLoc); } - if (moduleLoc.getScheme().equals("std") || moduleLoc.getScheme().equals("lib")) { + if (moduleLoc.getScheme().equals("std") || moduleLoc.getScheme().equals("mvn")) { return pathToModulename(modulePath, "/"); } @@ -840,7 +840,7 @@ private String pathToModulename(String modulePath, String folder) { if(moduleName.startsWith("/")){ moduleName = moduleName.substring(1, moduleName.length()); } - return moduleName.replace("/", "::"); + return moduleName.replace(Configuration.RASCAL_PATH_SEP, Configuration.RASCAL_MODULE_SEP); } private String moduleToDir(String module) { @@ -852,7 +852,7 @@ private ISourceLocation getFullURI(String path, ISourceLocation dir) throws URIS } public List listModuleEntries(String moduleRoot) { - assert !moduleRoot.endsWith("::"); + assert !moduleRoot.endsWith(Configuration.RASCAL_MODULE_SEP); final URIResolverRegistry reg = URIResolverRegistry.getInstance(); try { String modulePath = moduleToDir(moduleRoot); @@ -871,7 +871,7 @@ public List listModuleEntries(String moduleRoot) { } else if (module.indexOf('.') == -1 && reg.isDirectory(getFullURI(module, full))) { // a sub folder path - result.add(module + "::"); + result.add(module + Configuration.RASCAL_MODULE_SEP); } } } From 30dc484ad1e40315c1eafe081e532211ee97cdfe Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 18:39:09 +0200 Subject: [PATCH 33/66] rename --- src/org/rascalmpl/library/util/PathConfig.java | 6 +++--- src/org/rascalmpl/library/util/Reflective.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 59c59716627..48f6fab43fe 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -337,7 +337,7 @@ public static PathConfig fromSourceProjectMemberRascalManifest(ISourceLocation p * Pitfall: Note however that the current JVM instance can never escape * from loading classes from the rascal.jar that was given on its classpath. */ - public static ISourceLocation resolveDependencyFromResourcesOnCurrentClasspath(String projectName) throws IOException { + public static ISourceLocation resolveProjectOnClasspath(String projectName) throws IOException { RascalManifest mf = new RascalManifest(); Enumeration mfs = PathConfig.class.getClassLoader().getResources(RascalManifest.META_INF_RASCAL_MF); @@ -375,7 +375,7 @@ public static ISourceLocation resolveDependencyFromResourcesOnCurrentClasspath(S } public static ISourceLocation resolveCurrentRascalRuntimeJar() throws IOException { - return resolveDependencyFromResourcesOnCurrentClasspath("rascal"); + return resolveProjectOnClasspath("rascal"); } private static ISourceLocation inferProjectRoot(ISourceLocation member) { @@ -515,7 +515,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes // IDE features like "jump-to-definition" could be off. if (libProjectName.equals("rascal-lsp")) { try { - var loadedRascalLsp = resolveDependencyFromResourcesOnCurrentClasspath("rascal-lsp"); + var loadedRascalLsp = resolveProjectOnClasspath("rascal-lsp"); try (InputStream in = reg.getInputStream(loadedRascalLsp); InputStream in2 = reg.getInputStream(dep)) { var version = new Manifest(in).getMainAttributes().getValue("Specification-Version"); diff --git a/src/org/rascalmpl/library/util/Reflective.java b/src/org/rascalmpl/library/util/Reflective.java index 14a23c1ebef..4a0e51ce106 100644 --- a/src/org/rascalmpl/library/util/Reflective.java +++ b/src/org/rascalmpl/library/util/Reflective.java @@ -83,7 +83,7 @@ public IString getRascalVersion() { public ISourceLocation resolveProjectOnClasspath(IString projectName) { try { - return PathConfig.resolveDependencyFromResourcesOnCurrentClasspath(projectName.getValue()); + return PathConfig.resolveProjectOnClasspath(projectName.getValue()); } catch (IOException e) { throw RuntimeExceptionFactory.io(e.getMessage()); From 968d013fbda3a433e4b559e8d64a440f1a9dcc3a Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 18:50:24 +0200 Subject: [PATCH 34/66] renamed invalid to unknown location and removed the unused URI version --- src/org/rascalmpl/library/Messages.java | 17 +++++++++-------- src/org/rascalmpl/library/lang/csv/IO.java | 2 +- src/org/rascalmpl/library/util/PathConfig.java | 2 +- src/org/rascalmpl/uri/URIUtil.java | 16 +++------------- .../values/RascalFunctionValueFactory.java | 2 +- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index 253c40da8c7..488f26c6e20 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -116,14 +116,15 @@ else if (l2.hasOffsetLength()) { line = loc.getBeginLine(); } - String output - = loc.getPath() - + ":" - + String.format("%0" + lineWidth + "d", line) - + ":" - + String.format("%0" + colWidth + "d", col) - + ": " - + ((IString) msg.get("msg")).getValue(); + String output + = loc.getPath() + + ":" + + String.format("%0" + lineWidth + "d", line) + + ":" + + String.format("%0" + colWidth + "d", col) + + ": " + + ((IString) msg.get("msg")).getValue() + ; if (isError) { out.println("[ERROR] " + output); diff --git a/src/org/rascalmpl/library/lang/csv/IO.java b/src/org/rascalmpl/library/lang/csv/IO.java index 09ba995b919..dbdeeaab489 100644 --- a/src/org/rascalmpl/library/lang/csv/IO.java +++ b/src/org/rascalmpl/library/lang/csv/IO.java @@ -387,7 +387,7 @@ public IValue visitSet(Type type) throws RuntimeException { } @Override public IValue visitSourceLocation(Type type) throws RuntimeException { - return values.sourceLocation(URIUtil.invalidURI()); + return URIUtil.unknownLocation(); } @Override public IValue visitString(Type type) throws RuntimeException { diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 48f6fab43fe..95b9cd4f66b 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -62,7 +62,7 @@ public class PathConfig { private static final List defaultIgnores = Collections.emptyList(); private static final ISourceLocation defaultGeneratedSources = URIUtil.rootLocation("unknown"); private static final List defaultMessages = Collections.emptyList(); - private static final ISourceLocation defaultBin = URIUtil.rootLocation("unknown"); + private static final ISourceLocation defaultBin = URIUtil.unknownLocation(); private static final List defaultLibs = Collections.emptyList(); /** implementation detail of communicating with the `mvn` command */ diff --git a/src/org/rascalmpl/uri/URIUtil.java b/src/org/rascalmpl/uri/URIUtil.java index 763a82fb179..f413c6c3f66 100644 --- a/src/org/rascalmpl/uri/URIUtil.java +++ b/src/org/rascalmpl/uri/URIUtil.java @@ -172,21 +172,11 @@ private static ISourceLocation createLocation(String scheme, String authority, String path) throws URISyntaxException { return vf.sourceLocation(scheme, authority, path); } - - private static final URI invalidURI = URI.create("unknown:///"); - - /** - * Returns an URI which cannot be read/write to. - * @return - */ - public static URI invalidURI() { - return invalidURI; - } - private static final ISourceLocation invalidLocation = vf.sourceLocation(invalidURI); + private static final ISourceLocation unknownLocation = rootLocation("unknown"); - public static ISourceLocation invalidLocation() { - return invalidLocation; + public static ISourceLocation unknownLocation() { + return unknownLocation; } /** diff --git a/src/org/rascalmpl/values/RascalFunctionValueFactory.java b/src/org/rascalmpl/values/RascalFunctionValueFactory.java index 268d049479f..5e77d2cf679 100644 --- a/src/org/rascalmpl/values/RascalFunctionValueFactory.java +++ b/src/org/rascalmpl/values/RascalFunctionValueFactory.java @@ -500,7 +500,7 @@ protected IValue parse(String methodName, ISet filters, IString input, ISourceL protected IValue firstAmbiguity(String methodName, IString input) { try { - return parseObject(methodName, URIUtil.invalidLocation(), input.getValue().toCharArray(), false, false, vf.set()); + return parseObject(methodName, URIUtil.unknownLocation(), input.getValue().toCharArray(), false, false, vf.set()); } catch (ParseError pe) { ISourceLocation errorLoc = pe.getLocation(); From 2621744ee62970025fb29957f486e2dc8406743d Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 18:57:49 +0200 Subject: [PATCH 35/66] resolved the comments by @davylandman --- .../rascalmpl/library/util/PathConfig.java | 390 +++++++++--------- .../uri/StandardLibraryURIResolver.java | 2 +- 2 files changed, 196 insertions(+), 196 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 95b9cd4f66b..a36834a6273 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -42,45 +42,45 @@ import io.usethesource.vallang.type.TypeStore; public class PathConfig { - private static final IValueFactory vf = ValueFactoryFactory.getValueFactory(); - private final TypeFactory tf = TypeFactory.getInstance(); - private final TypeStore store = new TypeStore(); - - // WARNING: these definitions must reflect the definitions in `util::Reflective` - private final Type PathConfigType = tf.abstractDataType(store, "PathConfig"); - private final Type pathConfigConstructor = tf.constructor(store, PathConfigType, "pathConfig"); - - private final List srcs; - private final List libs; + private static final IValueFactory vf = ValueFactoryFactory.getValueFactory(); + private final TypeFactory tf = TypeFactory.getInstance(); + private final TypeStore store = new TypeStore(); + + // WARNING: these definitions must reflect the definitions in `util::Reflective` + private final Type PathConfigType = tf.abstractDataType(store, "PathConfig"); + private final Type pathConfigConstructor = tf.constructor(store, PathConfigType, "pathConfig"); + + private final List srcs; + private final List libs; private final ISourceLocation bin; - private final List ignores; - private final ISourceLocation generatedSources; - private final List messages; - - - // defaults are shared here because they occur in different use places. - private static final List defaultIgnores = Collections.emptyList(); - private static final ISourceLocation defaultGeneratedSources = URIUtil.rootLocation("unknown"); - private static final List defaultMessages = Collections.emptyList(); - private static final ISourceLocation defaultBin = URIUtil.unknownLocation(); + private final List ignores; + private final ISourceLocation generatedSources; + private final List messages; + + + // defaults are shared here because they occur in different use places. + private static final List defaultIgnores = Collections.emptyList(); + private static final ISourceLocation defaultGeneratedSources = URIUtil.unknownLocation(); + private static final List defaultMessages = Collections.emptyList(); + private static final ISourceLocation defaultBin = URIUtil.unknownLocation(); private static final List defaultLibs = Collections.emptyList(); /** implementation detail of communicating with the `mvn` command */ private static final String WINDOWS_ROOT_TRUSTSTORE_TYPE_DEFINITION = "-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT"; - public static enum RascalConfigMode { + public static enum RascalConfigMode { INTERPRETER, COMPILER } - - public PathConfig() { - srcs = Collections.emptyList(); - ignores = defaultIgnores; - bin = defaultBin; - libs = Collections.emptyList(); - generatedSources = defaultGeneratedSources; - messages = defaultMessages; - } + + public PathConfig() { + srcs = Collections.emptyList(); + ignores = defaultIgnores; + bin = defaultBin; + libs = Collections.emptyList(); + generatedSources = defaultGeneratedSources; + messages = defaultMessages; + } public PathConfig(IConstructor pcfg) throws IOException { this( @@ -94,26 +94,26 @@ public PathConfig(IConstructor pcfg) throws IOException { } public PathConfig(List srcs, List libs, ISourceLocation bin) { - this(srcs, libs, bin, defaultIgnores); - } - - public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores) { - this(srcs, libs, bin, ignores, defaultGeneratedSources); - } - - public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, ISourceLocation generatedSources) { + this(srcs, libs, bin, defaultIgnores); + } + + public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores) { + this(srcs, libs, bin, ignores, defaultGeneratedSources); + } + + public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, ISourceLocation generatedSources) { this(srcs, libs, bin, ignores, generatedSources, defaultMessages); } - - public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, ISourceLocation generatedSources, List messages) { - this.srcs = dedup(srcs); - this.ignores = dedup(ignores); - this.libs = dedup(libs); - this.bin = bin; - this.generatedSources = generatedSources; - this.messages = messages; - } - + + public PathConfig(List srcs, List libs, ISourceLocation bin, List ignores, ISourceLocation generatedSources, List messages) { + this.srcs = dedup(srcs); + this.ignores = dedup(ignores); + this.libs = dedup(libs); + this.bin = bin; + this.generatedSources = generatedSources; + this.messages = messages; + } + public PathConfig(IList srcs, IList libs, ISourceLocation bin) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); @@ -122,8 +122,8 @@ public PathConfig(IList srcs, IList libs, ISourceLocation bin) { this.generatedSources = defaultGeneratedSources; this.messages = defaultMessages; } - - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores) { + + public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; @@ -131,8 +131,8 @@ public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores) { this.generatedSources = defaultGeneratedSources; this.messages = defaultMessages; } - - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources) { + + public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; @@ -140,8 +140,8 @@ public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, IS this.generatedSources = generatedSources; this.messages = defaultMessages; } - - public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources, IList messages) { + + public PathConfig(IList srcs, IList libs, ISourceLocation bin, IList ignores, ISourceLocation generatedSources, IList messages) { this.srcs = initializeLocList(srcs); this.libs = initializeLocList(libs); this.bin = bin; @@ -196,111 +196,111 @@ private static List dedup(List list) { return filtered; } - - private static List convertLocs(IList locs){ - List result = new ArrayList<>(); - for(IValue p : locs){ - if(p instanceof ISourceLocation){ - result.add((ISourceLocation) p); - } else { - throw new RuntimeException("Path should contain source locations and not " + p.getClass().getName()); - } - } - - return result; - } + + private static List convertLocs(IList locs){ + List result = new ArrayList<>(); + for(IValue p : locs){ + if(p instanceof ISourceLocation){ + result.add((ISourceLocation) p); + } else { + throw new RuntimeException("Path should contain source locations and not " + p.getClass().getName()); + } + } + + return result; + } private static List convertMessages(IList locs){ - List result = new ArrayList<>(); - for(IValue p : locs){ - if(p instanceof IConstructor){ - result.add((IConstructor) p); - } else { - throw new RuntimeException("Messages should contain message constructors and not " + p.getClass().getName()); - } - } - - return result; - } - - String makeFileName(String qualifiedModuleName) { - return makeFileName(qualifiedModuleName, "rsc"); - } - - public static ISourceLocation getDefaultBin(){ + List result = new ArrayList<>(); + for(IValue p : locs){ + if(p instanceof IConstructor){ + result.add((IConstructor) p); + } else { + throw new RuntimeException("Messages should contain message constructors and not " + p.getClass().getName()); + } + } + + return result; + } + + String makeFileName(String qualifiedModuleName) { + return makeFileName(qualifiedModuleName, "rsc"); + } + + public static ISourceLocation getDefaultBin(){ return defaultBin; } - - public static ISourceLocation getDefaultGeneratedSources() { - return defaultGeneratedSources; - } + + public static ISourceLocation getDefaultGeneratedSources() { + return defaultGeneratedSources; + } - public static IList getDefaultIgnoresList() { - return convertLocs(defaultIgnores); - } - - private static IList convertLocs(List locs) { - IListWriter w = vf.listWriter(); - w.appendAll(locs); - return w.done(); + public static IList getDefaultIgnoresList() { + return convertLocs(defaultIgnores); + } + + private static IList convertLocs(List locs) { + IListWriter w = vf.listWriter(); + w.appendAll(locs); + return w.done(); } public static List getDefaultIgnores(){ - return Collections.unmodifiableList(defaultIgnores); - } - - public IValueFactory getValueFactory() { - return vf; - } - - public IList getSrcs() { - return vf.list(srcs.toArray(new IValue[0])); - } - - public ISourceLocation getGeneratedSources() { - return generatedSources; - } - - public IList getMessages() { - return vf.list(messages.toArray(new IValue[messages.size()])); - } - - public PathConfig addSourceLoc(ISourceLocation dir) throws IOException { - List extendedsrcs = new ArrayList(srcs); - extendedsrcs.add(dir); - return new PathConfig(extendedsrcs, libs, bin, ignores, generatedSources, messages); - } - + return Collections.unmodifiableList(defaultIgnores); + } + + public IValueFactory getValueFactory() { + return vf; + } + + public IList getSrcs() { + return vf.list(srcs.toArray(new IValue[0])); + } + + public ISourceLocation getGeneratedSources() { + return generatedSources; + } + + public IList getMessages() { + return vf.list(messages.toArray(new IValue[messages.size()])); + } + + public PathConfig addSourceLoc(ISourceLocation dir) throws IOException { + List extendedsrcs = new ArrayList(srcs); + extendedsrcs.add(dir); + return new PathConfig(extendedsrcs, libs, bin, ignores, generatedSources, messages); + } + public PathConfig setGeneratedSources(ISourceLocation dir) throws IOException { return new PathConfig(srcs, libs, bin, ignores, dir, messages); } - - public IList getIgnores() { - return vf.list(ignores.toArray(new IValue[0])); - } - - public PathConfig addIgnoreLoc(ISourceLocation dir) throws IOException { - List extendedignores = new ArrayList(ignores); - extendedignores.add(dir); - return new PathConfig(srcs, libs, bin, extendedignores, generatedSources, messages); - } - - public IList getLibs() { + + public IList getIgnores() { + return vf.list(ignores.toArray(new IValue[0])); + } + + public PathConfig addIgnoreLoc(ISourceLocation dir) throws IOException { + List extendedignores = new ArrayList(ignores); + extendedignores.add(dir); + return new PathConfig(srcs, libs, bin, extendedignores, generatedSources, messages); + } + + public IList getLibs() { return vf.list(libs.toArray(new IValue[0])); } public IList getLibsAndTarget() { return getLibs().append(getBin()); } - - public PathConfig addLibLoc(ISourceLocation dir) throws IOException { - List extendedlibs = new ArrayList(libs); - extendedlibs.add(dir); - return new PathConfig(srcs, extendedlibs, bin, ignores, generatedSources, messages); - } - + + public PathConfig addLibLoc(ISourceLocation dir) throws IOException { + List extendedlibs = new ArrayList(libs); + extendedlibs.add(dir); + return new PathConfig(srcs, extendedlibs, bin, ignores, generatedSources, messages); + } + /** - * This will create a PathConfig by learning from the MANIFEST/RASCAL.MF file where the sources + * This will create a PathConfig by learning from the MANIFEST/RASCAL.MF file where the sources * are, which libraries to reference and which classpath entries to add. If this PathConfig is * for the interpreter it adds more folders to the source path than if its for the compiler. * @@ -308,12 +308,12 @@ public PathConfig addLibLoc(ISourceLocation dir) throws IOException { * correspondence, then the target and source folders of the projects are added rather then * the jar files. For compiler configs this works differently than for interpreter configs. * The latter adds source folders to the sources while the former adds target folders to the libraries. - * - * @param manifest the source location of the folder which contains MANIFEST/RASCAL.MF. - * @return + * + * @param manifest the source location of the folder which contains MANIFEST/RASCAL.MF. + * @return * @throws URISyntaxException - */ - public static PathConfig fromSourceProjectMemberRascalManifest(ISourceLocation projectMember, RascalConfigMode mode) throws IOException { + */ + public static PathConfig fromSourceProjectMemberRascalManifest(ISourceLocation projectMember, RascalConfigMode mode) throws IOException { if (!URIResolverRegistry.getInstance().isDirectory(projectMember)) { projectMember = URIUtil.getParentLocation(projectMember); } @@ -426,8 +426,8 @@ public PathConfig parse(String pathConfigString) throws IOException { } } - /** - * This creates a PathConfig instance by learning from the `MANIFEST/RASCAL.MF` file where the sources + /** + * This creates a PathConfig instance by learning from the `MANIFEST/RASCAL.MF` file where the sources * are, and from `pom.xml` which libraries to reference. If this PathConfig is * for the interpreter it adds more folders to the source path than if its for the compiler. * @@ -455,13 +455,13 @@ public PathConfig parse(String pathConfigString) throws IOException { * * Clients of this method must promote the messages list to a UI facing log, such as the diagnostics * or problems view in an IDE, an error LOG for a CI and stderr or stdout for console applications. - * - * @param manifest the source location of the folder which contains MANIFEST/RASCAL.MF. + * + * @param manifest the source location of the folder which contains MANIFEST/RASCAL.MF. * @param RascalConfigMode.INTERPRETER | RascalConfigMode.COMPILER - * @return a PathConfig instance, fully informed to start initializing a Rascal compiler or interpreter, and including a list of revelant info, warning and error messages. - * @throws nothing, because all errors are collected in a messages field of the PathConfig. - */ - public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifestRoot, RascalConfigMode mode) { + * @return a PathConfig instance, fully informed to start initializing a Rascal compiler or interpreter, and including a list of revelant info, warning and error messages. + * @throws nothing, because all errors are collected in a messages field of the PathConfig. + */ + public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifestRoot, RascalConfigMode mode) { RascalManifest manifest = new RascalManifest(); URIResolverRegistry reg = URIResolverRegistry.getInstance(); IRascalValueFactory vf = IRascalValueFactory.getInstance(); @@ -646,7 +646,7 @@ else if (rascalProject != null) { vf.list(), generatedSources, messages.done()); - } + } private static void addLibraryToSourcePath(URIResolverRegistry reg, IListWriter srcsWriter, IListWriter messages, ISourceLocation jar) { if (!reg.exists(URIUtil.getChildLocation(jar, RascalManifest.META_INF_RASCAL_MF))) { @@ -695,7 +695,7 @@ private static ISourceLocation setTargetScheme(ISourceLocation projectLoc) { private static ISourceLocation getRascalMfLocation(ISourceLocation project) { return URIUtil.getChildLocation(project, RascalManifest.META_INF_RASCAL_MF); } - + private static ISourceLocation getPomXmlLocation(ISourceLocation project) { try { ISourceLocation pomxml = URIUtil.getChildLocation(project, "pom.xml"); @@ -714,7 +714,7 @@ private static ISourceLocation getPomXmlLocation(ISourceLocation project) { * @return * @throws IOException */ - private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) throws IOException { + private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) throws IOException { var pomxml = getPomXmlLocation(manifestRoot); manifestRoot = URIResolverRegistry.getInstance().logicalToPhysical(manifestRoot); @@ -804,36 +804,36 @@ private static String trustStoreFix() { public ISourceLocation getBin() { return bin; } - - String makeFileName(String qualifiedModuleName, String extension) { - return qualifiedModuleName.replaceAll("::", "/") + "." + extension; - } - + + String makeFileName(String qualifiedModuleName, String extension) { + return qualifiedModuleName.replaceAll("::", "/") + "." + extension; + } + public String getModuleName(ISourceLocation moduleLoc) throws IOException{ - String modulePath = moduleLoc.getPath(); - if(!modulePath.endsWith(".rsc")){ - throw new IOException("Not a Rascal source file: " + moduleLoc); - } + String modulePath = moduleLoc.getPath(); + if(!modulePath.endsWith(".rsc")){ + throw new IOException("Not a Rascal source file: " + moduleLoc); + } - if (moduleLoc.getScheme().equals("std") || moduleLoc.getScheme().equals("mvn")) { + if (moduleLoc.getScheme().equals("std") || moduleLoc.getScheme().equals("mvn")) { return pathToModulename(modulePath, "/"); - } + } - for(ISourceLocation dir : srcs){ - if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ - return pathToModulename(modulePath, dir.getPath()); - } - } + for(ISourceLocation dir : srcs){ + if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ + return pathToModulename(modulePath, dir.getPath()); + } + } - for (ISourceLocation dir : libs) { - if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ + for (ISourceLocation dir : libs) { + if(modulePath.startsWith(dir.getPath()) && moduleLoc.getScheme() == dir.getScheme()){ return pathToModulename(modulePath, dir.getPath()); } - } + } - throw new IOException("No module name found for " + moduleLoc + "\n" + this); + throw new IOException("No module name found for " + moduleLoc + "\n" + this); - } + } private String pathToModulename(String modulePath, String folder) { String moduleName = modulePath.replaceFirst(folder, "").replace(".rsc", ""); @@ -843,7 +843,7 @@ private String pathToModulename(String modulePath, String folder) { return moduleName.replace(Configuration.RASCAL_PATH_SEP, Configuration.RASCAL_MODULE_SEP); } - private String moduleToDir(String module) { + private String moduleToDir(String module) { return module.replaceAll(Configuration.RASCAL_MODULE_SEP, Configuration.RASCAL_PATH_SEP); } @@ -851,7 +851,7 @@ private ISourceLocation getFullURI(String path, ISourceLocation dir) throws URIS return URIUtil.getChildLocation(dir, path); } - public List listModuleEntries(String moduleRoot) { + public List listModuleEntries(String moduleRoot) { assert !moduleRoot.endsWith(Configuration.RASCAL_MODULE_SEP); final URIResolverRegistry reg = URIResolverRegistry.getInstance(); try { @@ -892,25 +892,25 @@ else if (module.indexOf('.') == -1 && reg.isDirectory(getFullURI(module, full))) * Convert PathConfig Java object to pathConfig Rascal constructor for use * in Rascal code or for serialization and printing. */ - public IConstructor asConstructor() { - Map config = new HashMap<>(); - - config.put("srcs", getSrcs()); - config.put("ignores", getIgnores()); - config.put("bin", getBin()); - config.put("libs", getLibs()); - config.put("generatedSources", getGeneratedSources()); - config.put("messages", getMessages()); - - return vf.constructor(pathConfigConstructor, new IValue[0], config); - } - + public IConstructor asConstructor() { + Map config = new HashMap<>(); + + config.put("srcs", getSrcs()); + config.put("ignores", getIgnores()); + config.put("bin", getBin()); + config.put("libs", getLibs()); + config.put("generatedSources", getGeneratedSources()); + config.put("messages", getMessages()); + + return vf.constructor(pathConfigConstructor, new IValue[0], config); + } + /** * Overview of the contents of the current configuration for debugging purposes. * Not necessarily for end-user UI, although it's better than nothing. */ - public String toString(){ - StringWriter w = new StringWriter(); + public String toString(){ + StringWriter w = new StringWriter(); w.append("Path configuration items:") .append("srcs: ").append(getSrcs().toString()).append("\n") .append("ignores: ").append(getIgnores().toString()).append("\n") diff --git a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java index d6e3d824557..ddb1514fc75 100644 --- a/src/org/rascalmpl/uri/StandardLibraryURIResolver.java +++ b/src/org/rascalmpl/uri/StandardLibraryURIResolver.java @@ -38,7 +38,7 @@ private static ISourceLocation resolveCurrentRascalJar() { } catch (IOException e) { // this will be reported elsewhere in PathConfig.messages - - return null; + return URIUtil.unknownLocation(); } } From 564dde95888d1912c13ea7e78fec24380fcdfe48 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 19:17:30 +0200 Subject: [PATCH 36/66] mvn hostname syntax changed from ! separators to ~ for compatibility with URL and URI hostname standards --- .../lang/rascal/tests/basic/Locations.rsc | 2 +- src/org/rascalmpl/library/util/PathConfig.java | 2 +- .../repl/TerminalProgressBarMonitor.java | 4 ++-- .../uri/file/MavenRepositoryURIResolver.java | 18 +++++++++++------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc b/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc index 3843d3081d3..eccc3cbac2a 100644 --- a/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc +++ b/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc @@ -578,7 +578,7 @@ test bool mvnSchemeTest() { // check whether the implementation of the scheme holds the contract specified in the assert for (jar <- jarFiles, path(groupId, artifactId, version) := parseMavenLocalRepositoryPath(jar)) { // this is the contract: - mvnLoc = |mvn://!!|; + mvnLoc = |mvn://~~|; assert resolveLocation(mvnLoc) == resolveLocation(jar) : " != ' jar: diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index a36834a6273..632dcc03d98 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -437,7 +437,7 @@ public PathConfig parse(String pathConfigString) throws IOException { * some level of backward compatibility until everybody has moved to using pom.xml. * * If library dependencies exist for _open_ projects in the same IDE, via the `project://` - * correspondence with `mvn://!!`, then the target and source folders of + * correspondence with `mvn://~~`, then the target and source folders of * those projects are added to the configuration instead of the jar files. * For compiler configs this works differently than for interpreter configs. * The latter adds source folders to the `srcs` while the former adds target folders to the `libs`. diff --git a/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java b/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java index c9cb6625947..e812fa4c058 100644 --- a/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java +++ b/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java @@ -16,8 +16,8 @@ import org.rascalmpl.debug.IRascalMonitor; import io.usethesource.vallang.ISourceLocation; -import jline.Terminal; -import jline.internal.Configuration; +import org.rascalmpl.jline.Terminal; +import org.rascalmpl.jline.internal.Configuration; /** * The terminal progress bar monitor wraps the standard output stream to be able to monitor diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 583d49b10c7..26d98e81849 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -18,9 +18,9 @@ * Finds jar files (and what's inside) relative to the root of the LOCAL Maven repository. * For a discussion REMOTE repositories see below. * - * We use `mvn://!!/` as the general scheme; - * also `mvn://!!/!/` is allowed to make sure the - * root `mvn://!!/` remains a jar file unambiguously. + * We use `mvn://~~/` as the general scheme; + * also `mvn://~~/~/` is allowed to make sure the + * root `mvn://~~/` remains a jar file unambiguously. * * So the authority encodes the identity of the maven project and the path encodes * what's inside the respective jar file. This is analogous to other schemes for projects @@ -30,7 +30,7 @@ * Here `version` is an arbitrary string with lots of numbers, dots, dashed and underscores. * Typically we'd expect the semantic versioning scheme here with some release tag, but * real maven projects frequently do not adhere to that standard. Hence we have to be "free" - * here and allow lots of funny version strings. This is also why we use ! again to separate + * here and allow lots of funny version strings. This is also why we use ~ again to separate * the version from the artifactId. * * Locations with the `mvn` scheme are typically produced by configuration code that uses @@ -82,8 +82,8 @@ public class MavenRepositoryURIResolver extends AliasedFileResolver { private static String localRepoLocationCache; private final Pattern authorityRegEx - = Pattern.compile("^([a-zA-Z0-9-_.]+?)[!]([a-zA-Z0-9-_.]+)([!][a-zA-Z0-9\\-_.]+)$"); - // groupId ! artifactId ! optionAlComplexVersionString + = Pattern.compile("^([a-zA-Z0-9-_.]+?)[~]([a-zA-Z0-9-_.]+)([~][a-zA-Z0-9\\-_.]+)$"); + // groupId ~ artifactId ~ optionAlComplexVersionString public MavenRepositoryURIResolver() throws IOException { super("mvn", inferMavenRepositoryLocation()); @@ -226,6 +226,10 @@ public ISourceLocation resolve(ISourceLocation input) throws IOException { } } + public static ISourceLocation make(String groupId, String artifactId, String version, String path) { + return URIUtil.correctLocation("mvn", groupId + "~" + artifactId + "~" + version, path); + } + /** * Shortens a location of a jar file that points into a local maven repository, and * leaves all other locations as-is. @@ -247,7 +251,7 @@ public static ISourceLocation mavenize(ISourceLocation loc) { String artifactId = URIUtil.getLocationName(URIUtil.getParentLocation(URIUtil.getParentLocation(relative))); String version = URIUtil.getLocationName(URIUtil.getParentLocation(relative)); - return URIUtil.correctLocation("mvn", groupId + "!" + artifactId + "!" + version, ""); + return make(groupId, artifactId, version, ""); } return loc; From 3fd5e120121e82493930952b68bda6b92d89347c Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 19:43:42 +0200 Subject: [PATCH 37/66] replaced ~ separator by -- for compliance with also the DNS standards --- .../library/lang/rascal/tests/basic/Locations.rsc | 2 +- .../uri/file/MavenRepositoryURIResolver.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc b/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc index eccc3cbac2a..8ff62ef516a 100644 --- a/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc +++ b/src/org/rascalmpl/library/lang/rascal/tests/basic/Locations.rsc @@ -578,7 +578,7 @@ test bool mvnSchemeTest() { // check whether the implementation of the scheme holds the contract specified in the assert for (jar <- jarFiles, path(groupId, artifactId, version) := parseMavenLocalRepositoryPath(jar)) { // this is the contract: - mvnLoc = |mvn://~~|; + mvnLoc = |mvn://----|; assert resolveLocation(mvnLoc) == resolveLocation(jar) : " != ' jar: diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 26d98e81849..09cc1bd60dd 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -18,9 +18,9 @@ * Finds jar files (and what's inside) relative to the root of the LOCAL Maven repository. * For a discussion REMOTE repositories see below. * - * We use `mvn://~~/` as the general scheme; - * also `mvn://~~/~/` is allowed to make sure the - * root `mvn://~~/` remains a jar file unambiguously. + * We use `mvn://----/` as the general scheme; + * also `mvn://----/!/` is allowed to make sure the + * root `mvn://----/` remains a jar file unambiguously. * * So the authority encodes the identity of the maven project and the path encodes * what's inside the respective jar file. This is analogous to other schemes for projects @@ -30,7 +30,7 @@ * Here `version` is an arbitrary string with lots of numbers, dots, dashed and underscores. * Typically we'd expect the semantic versioning scheme here with some release tag, but * real maven projects frequently do not adhere to that standard. Hence we have to be "free" - * here and allow lots of funny version strings. This is also why we use ~ again to separate + * here and allow lots of funny version strings. This is also why we use -- to separate * the version from the artifactId. * * Locations with the `mvn` scheme are typically produced by configuration code that uses @@ -82,8 +82,8 @@ public class MavenRepositoryURIResolver extends AliasedFileResolver { private static String localRepoLocationCache; private final Pattern authorityRegEx - = Pattern.compile("^([a-zA-Z0-9-_.]+?)[~]([a-zA-Z0-9-_.]+)([~][a-zA-Z0-9\\-_.]+)$"); - // groupId ~ artifactId ~ optionAlComplexVersionString + = Pattern.compile("^([a-zA-Z0-9-_.]+?)[-][-]([a-zA-Z0-9-_.]+)([-][-][a-zA-Z0-9\\-_.]+)$"); + // groupId -- artifactId -- optionAlComplexVersionString public MavenRepositoryURIResolver() throws IOException { super("mvn", inferMavenRepositoryLocation()); @@ -227,7 +227,7 @@ public ISourceLocation resolve(ISourceLocation input) throws IOException { } public static ISourceLocation make(String groupId, String artifactId, String version, String path) { - return URIUtil.correctLocation("mvn", groupId + "~" + artifactId + "~" + version, path); + return URIUtil.correctLocation("mvn", groupId + "--" + artifactId + "--" + version, path); } /** From 18581ead628159d00fa356138298e7198fba8e24 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Tue, 24 Sep 2024 19:55:57 +0200 Subject: [PATCH 38/66] comment fixed --- src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 09cc1bd60dd..44ab52182f4 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -177,7 +177,7 @@ public ISourceLocation resolve(ISourceLocation input) throws IOException { } else { // the authority encodes the group, name and version of a maven dependency - // org.rascalmpl.rascal-34.2.0-RC2 + // org.rascalmpl--rascal--34.2.0-RC2 var m = authorityRegEx.matcher(authority); if (m.matches()) { From 3a16fd9f3b2f7ec6160db1855f3e5d6ff315f483 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 25 Sep 2024 08:56:05 +0200 Subject: [PATCH 39/66] fix minor hickups after changing mvn scheme syntax and confusions with renamed packages of jline --- src/org/rascalmpl/library/util/PathConfig.java | 3 ++- src/org/rascalmpl/repl/TerminalProgressBarMonitor.java | 5 +++-- src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 632dcc03d98..accfdf9d1cb 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -619,7 +619,8 @@ else if (rascalProject != null) { } try (InputStream mfi = manifest.manifest(manifestRoot)) { - if (!new Manifest(mfi).getMainAttributes().getValue("Require-Libraries").isEmpty()) { + var reqlibs = new Manifest(mfi).getMainAttributes().getValue("Require-Libraries"); + if (reqlibs != null && !reqlibs.isEmpty()) { messages.append(Messages.info("Require-Libraries in RASCAL.MF are not used anymore. Please use Maven dependencies in pom.xml.", getRascalMfLocation(manifestRoot))); } } diff --git a/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java b/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java index e812fa4c058..1467dccb770 100644 --- a/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java +++ b/src/org/rascalmpl/repl/TerminalProgressBarMonitor.java @@ -16,8 +16,9 @@ import org.rascalmpl.debug.IRascalMonitor; import io.usethesource.vallang.ISourceLocation; -import org.rascalmpl.jline.Terminal; -import org.rascalmpl.jline.internal.Configuration; +import jline.Terminal; +import jline.internal.Configuration; + /** * The terminal progress bar monitor wraps the standard output stream to be able to monitor diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 44ab52182f4..7a16ec7d58b 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -82,7 +82,7 @@ public class MavenRepositoryURIResolver extends AliasedFileResolver { private static String localRepoLocationCache; private final Pattern authorityRegEx - = Pattern.compile("^([a-zA-Z0-9-_.]+?)[-][-]([a-zA-Z0-9-_.]+)([-][-][a-zA-Z0-9\\-_.]+)$"); + = Pattern.compile("^([a-zA-Z0-9-_.]+?)[\\-][\\-]([a-zA-Z0-9-_.]+)[\\-][\\-]([a-zA-Z0-9\\-_.]+)$"); // groupId -- artifactId -- optionAlComplexVersionString public MavenRepositoryURIResolver() throws IOException { @@ -185,7 +185,7 @@ public ISourceLocation resolve(ISourceLocation input) throws IOException { String name = m.group(2); String version = m.group(3); - version = version == null ? "" : version.substring(1); + // version = version == null ? "" : version.substring(1); String jarPath = group.replaceAll("\\.", "/") From 497f6cadf4154e494c4ceb29da85423d2cadf3f8 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 25 Sep 2024 13:16:38 +0200 Subject: [PATCH 40/66] rascalMF generation was broken (no empty line at end). Also factored functions to generate pom.xml and RASCAL.MF independently, for later use in quickfixes --- src/org/rascalmpl/library/util/Reflective.rsc | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/library/util/Reflective.rsc b/src/org/rascalmpl/library/util/Reflective.rsc index 51fa8dc7e7d..2e5b230ec45 100644 --- a/src/org/rascalmpl/library/util/Reflective.rsc +++ b/src/org/rascalmpl/library/util/Reflective.rsc @@ -390,9 +390,9 @@ void newRascalProject(loc folder, str group="org.rascalmpl", str version="0.1.0- } mkDirectory(pomFile(folder).parent); - writeFile(pomFile(folder), pomXml(name, group, version)); + newRascalPomFile(folder, name=name, group=group, version=version); mkDirectory(metafile(folder).parent); - writeFile(metafile(folder), rascalMF(name)); + newRascalMfFile(folder, name=name); mkDirectory(folder + "src/main/rascal"); writeFile((folder + "src/main/rascal") + "Main.rsc", emptyModule()); } @@ -413,7 +413,34 @@ private str rascalMF(str name) = "Manifest-Version: 0.0.1 'Project-Name: 'Source: src/main/rascal - "; + ' + '"; + +@synopsis{Create a new META-INF/RASCAL.MF file.} +@description{ +The `folder` parameter should point to the root of a project folder. +The name of the project will be derived from the name of that folder +and a META-INF/RASCAL.MF file will be generated and written. + +The folder is created if it does not exist already. +} +void newRascalMfFile(loc folder, str name=folder.file) { + mkDirectory(folder); + writeFile(metafile(folder), rascalMF(name)); +} + +@synopsis{Create a new pom.xml for a Rascal project} +@description{ +The `folder` parameter should point to the root of a project folder. +The name of the project will be derived from the name of that folder +and a pom.xml file will be generated and written. + +The folder is created if it does not exist already. +} +void newRascalPomFile(loc folder, str name=folder.file, str group="org.rascalmpl", str version="0.1.0-SNAPSHOT") { + mkDirectory(folder); + writeFile(pomFile(folder), pomXml(name, group, version)); +} private str pomXml(str name, str group, str version) = "\ From d571153986722cc74561a9c2154c65a96ee0840b Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 25 Sep 2024 13:29:27 +0200 Subject: [PATCH 41/66] refactoring --- src/org/rascalmpl/library/util/Reflective.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/library/util/Reflective.rsc b/src/org/rascalmpl/library/util/Reflective.rsc index 2e5b230ec45..bdb354a73bc 100644 --- a/src/org/rascalmpl/library/util/Reflective.rsc +++ b/src/org/rascalmpl/library/util/Reflective.rsc @@ -389,10 +389,10 @@ void newRascalProject(loc folder, str group="org.rascalmpl", str version="0.1.0- throw "Folder should have only lowercase characters, digits and dashes from [a-z0-9\\-]"; } - mkDirectory(pomFile(folder).parent); + newRascalPomFile(folder, name=name, group=group, version=version); - mkDirectory(metafile(folder).parent); newRascalMfFile(folder, name=name); + mkDirectory(folder + "src/main/rascal"); writeFile((folder + "src/main/rascal") + "Main.rsc", emptyModule()); } @@ -425,7 +425,7 @@ and a META-INF/RASCAL.MF file will be generated and written. The folder is created if it does not exist already. } void newRascalMfFile(loc folder, str name=folder.file) { - mkDirectory(folder); + mkDirectory(rascalMF(name).parent); writeFile(metafile(folder), rascalMF(name)); } From 4b6dcb9f1d91e8bf83cd5aba76fd448040e7990a Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 25 Sep 2024 14:18:06 +0200 Subject: [PATCH 42/66] removed duplicate addition of rascal runtime in case of a dependency on the rascal project in the pom file --- src/org/rascalmpl/library/util/PathConfig.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index accfdf9d1cb..91dee68aa1f 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -501,6 +501,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes // * Only the rascal project itself is never used from source project, to avoid // complex bootstrapping situations. + for (IValue elem : mavenClasspath) { ISourceLocation dep = (ISourceLocation) elem; String libProjectName = manifest.getManifestProjectName(manifest.manifest(dep)); @@ -553,6 +554,9 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes // error messages are transitively collected messages.appendAll(childConfig.getMessages()); } + else if (dep == rascalProject) { + // not adding it again (we added rascal already above) + } else { // just a pre-installed dependency in the local maven repository if (!reg.exists(dep)) { From 663772188c16e1e7a9404168edb61967a7e99fac Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 25 Sep 2024 20:32:46 +0200 Subject: [PATCH 43/66] added two print functions to PathConfig for reuse purposes --- .../rascalmpl/library/util/PathConfig.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 91dee68aa1f..f5584977129 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.net.URISyntaxException; @@ -781,6 +782,32 @@ private static String computeMavenCommandName() { } } + /** + * Prints what users need to know about how the interpreter is configured with this PathConfig + */ + public void printInterpreterConfigurationStatus(PrintWriter out) { + out.println("Module paths:"); + getSrcs().forEach((f) -> out.println(" ".repeat(4) + f)); + out.println("JVM library classpath:"); + getLibsAndTarget().forEach((l) -> out.println(" ".repeat(4) + l)); + out.flush(); + } + + /** + * Prints what users need to know about how the compiler is configured with this PathConfig + */ + public void printCompilerConfigurationStatus(PrintWriter out) { + out.println("Source paths:"); + getSrcs().forEach((f) -> out.println(" ".repeat(4) + f)); + out.println("Compiler target folder:"); + out.println(" ".repeat(4) + getBin()); + out.println("Compiler generated sources folder:"); + out.println(" ".repeat(4) + getGeneratedSources()); + out.println("Rascal and Java library classpath:"); + getLibsAndTarget().forEach((l) -> out.println(" ".repeat(4) + l)); + out.flush(); + } + private static void installNecessaryMavenPlugins(String mvnCommand) throws IOException { try { ProcessBuilder processBuilder = new ProcessBuilder(mvnCommand, From d5bef4be8f93a0ec19e484aff9fcd11737606f78 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Fri, 6 Dec 2024 17:45:18 +0100 Subject: [PATCH 44/66] Fix issue that target folders of open dependencies were ignored --- src/org/rascalmpl/library/util/PathConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index f5584977129..5a0f2738258 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -543,8 +543,10 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes switch (mode) { case INTERPRETER: srcsWriter.appendAll(childConfig.getSrcs()); + libsWriter.append(childConfig.getBin()); break; case COMPILER: + // FIXME (?): Add something to `srcsWriter` here? libsWriter.append(setTargetScheme(projectLoc)); break; } From 0da31bb8c1e906e489ef255165b91ae176f6bcfb Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 9 Dec 2024 08:59:36 +0100 Subject: [PATCH 45/66] Remove redundant FIXME --- src/org/rascalmpl/library/util/PathConfig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 5a0f2738258..56c205af84c 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -546,7 +546,6 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes libsWriter.append(childConfig.getBin()); break; case COMPILER: - // FIXME (?): Add something to `srcsWriter` here? libsWriter.append(setTargetScheme(projectLoc)); break; } From 2dcfbfaf0dee2e4f023666e0af415d408b98e744 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 23 Dec 2024 15:08:44 +0100 Subject: [PATCH 46/66] Add placeholder source folder/module for typepal --- META-INF/RASCAL.MF | 2 +- src/org/rascalmpl/typepal/Typepal.rsc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/org/rascalmpl/typepal/Typepal.rsc diff --git a/META-INF/RASCAL.MF b/META-INF/RASCAL.MF index d3977080a63..c43531825ba 100644 --- a/META-INF/RASCAL.MF +++ b/META-INF/RASCAL.MF @@ -1,5 +1,5 @@ Project-Name: rascal -Source: src/org/rascalmpl/library,test/org/rascalmpl/benchmark,test//org/rascalmpl/test/data +Source: src/org/rascalmpl/library,src/org/rascalmpl/typepal,test/org/rascalmpl/benchmark,test//org/rascalmpl/test/data Courses: src/org/rascalmpl/courses diff --git a/src/org/rascalmpl/typepal/Typepal.rsc b/src/org/rascalmpl/typepal/Typepal.rsc new file mode 100644 index 00000000000..12676023bcd --- /dev/null +++ b/src/org/rascalmpl/typepal/Typepal.rsc @@ -0,0 +1,5 @@ +module Typepal + +// TODO: This is intended to be a temporary placeholder module (useful for +// testing `PathConfig` changes). It should be removed when `typepal` has been +// merged into `rascal`. \ No newline at end of file From 24ab304f3baf15b4cc747d09b9465127193f34c4 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 23 Dec 2024 15:25:56 +0100 Subject: [PATCH 47/66] Print also physical location of `std` in `printInterpreterConfigurationStatus` --- src/org/rascalmpl/library/util/PathConfig.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 56c205af84c..d9ce021f1e9 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -788,7 +788,18 @@ private static String computeMavenCommandName() { */ public void printInterpreterConfigurationStatus(PrintWriter out) { out.println("Module paths:"); - getSrcs().forEach((f) -> out.println(" ".repeat(4) + f)); + getSrcs().forEach(f -> { + var l = (ISourceLocation) f; + var s = " ".repeat(4) + l; + if (l.getScheme().equals("std")) { + try { + s += " at " + URIResolverRegistry.getInstance().logicalToPhysical(l); + } catch (IOException e) { + s += " at unknown physical location"; + } + } + out.println(s); + }); out.println("JVM library classpath:"); getLibsAndTarget().forEach((l) -> out.println(" ".repeat(4) + l)); out.flush(); From 0fa9203556e4fc0a36a11f5e77189cabf0494897 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 23 Dec 2024 15:28:53 +0100 Subject: [PATCH 48/66] Specialize computation of module path for `rascal` source folders --- .../rascalmpl/library/util/PathConfig.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index d9ce021f1e9..014336ffb73 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -16,8 +16,10 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.BiPredicate; import java.util.jar.Manifest; import org.rascalmpl.interpreter.Configuration; @@ -26,6 +28,7 @@ import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; import org.rascalmpl.uri.file.MavenRepositoryURIResolver; +import org.rascalmpl.uri.jar.JarURIResolver; import org.rascalmpl.values.IRascalValueFactory; import org.rascalmpl.values.ValueFactoryFactory; @@ -635,8 +638,34 @@ else if (rascalProject != null) { messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); } + // The `rascal` project has two special source folders (`.../library` + // and `.../typepal`). The versions of these two folders in the + // "current" `rascal` (as per `resolveCurrentRascalRuntimeJar()`) are + // always included in the module path. All remaining source folders of + // the `rascal` project are always excluded, except when the current + // project happens to be `rascal` itself (in which case they are + // normally included). + ISourceLocation currentRascal = URIUtil.unknownLocation(); + try { + currentRascal = JarURIResolver.jarify(resolveCurrentRascalRuntimeJar()); + } catch (IOException e) { + messages.append(Messages.error(e.getMessage(), manifestRoot)); + } + + var rascalSpecialSrcs = new LinkedHashMap(); // Keep insertion order for predictable output + rascalSpecialSrcs.put(URIUtil.rootLocation("std"),"src/org/rascalmpl/library"); + rascalSpecialSrcs.put(URIUtil.getChildLocation(currentRascal, "org/rascalmpl/typepal"), "src/org/rascalmpl/typepal"); + + BiPredicate isRascalSpecialSrc = (project, src) -> + "rascal".equals(project) && rascalSpecialSrcs.values().contains(src); + + srcsWriter.appendAll(rascalSpecialSrcs.keySet()); for (String srcName : manifest.getSourceRoots(manifestRoot)) { + if (isRascalSpecialSrc.test(projectName, srcName)) { + continue; // Don't append special source folders again + } + var srcFolder = URIUtil.getChildLocation(manifestRoot, srcName); if (!reg.exists(srcFolder) || !reg.isDirectory(srcFolder)) { From 7766602c4dfbd881a2d4560a3882a6623dfeb7aa Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Tue, 24 Dec 2024 11:26:36 +0100 Subject: [PATCH 49/66] Refine approach to add `rascal` source folders to path configs (and move code to separate method) --- .../rascalmpl/library/util/PathConfig.java | 103 ++++++++++++------ 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 014336ffb73..2e2b87d5301 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -16,10 +16,9 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.BiPredicate; +import java.util.function.Predicate; import java.util.jar.Manifest; import org.rascalmpl.interpreter.Configuration; @@ -638,41 +637,22 @@ else if (rascalProject != null) { messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); } - // The `rascal` project has two special source folders (`.../library` - // and `.../typepal`). The versions of these two folders in the - // "current" `rascal` (as per `resolveCurrentRascalRuntimeJar()`) are - // always included in the module path. All remaining source folders of - // the `rascal` project are always excluded, except when the current - // project happens to be `rascal` itself (in which case they are - // normally included). - - ISourceLocation currentRascal = URIUtil.unknownLocation(); try { - currentRascal = JarURIResolver.jarify(resolveCurrentRascalRuntimeJar()); + addRascalToSourcePath(srcsWriter); } catch (IOException e) { - messages.append(Messages.error(e.getMessage(), manifestRoot)); + messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); } - var rascalSpecialSrcs = new LinkedHashMap(); // Keep insertion order for predictable output - rascalSpecialSrcs.put(URIUtil.rootLocation("std"),"src/org/rascalmpl/library"); - rascalSpecialSrcs.put(URIUtil.getChildLocation(currentRascal, "org/rascalmpl/typepal"), "src/org/rascalmpl/typepal"); - - BiPredicate isRascalSpecialSrc = (project, src) -> - "rascal".equals(project) && rascalSpecialSrcs.values().contains(src); - - srcsWriter.appendAll(rascalSpecialSrcs.keySet()); - for (String srcName : manifest.getSourceRoots(manifestRoot)) { - if (isRascalSpecialSrc.test(projectName, srcName)) { - continue; // Don't append special source folders again - } + if (!projectName.equals("rascal")) { // Don't add `rascal` again + for (String srcName : manifest.getSourceRoots(manifestRoot)) { + var srcFolder = URIUtil.getChildLocation(manifestRoot, srcName); + + if (!reg.exists(srcFolder) || !reg.isDirectory(srcFolder)) { + messages.append(Messages.error("Source folder " + srcFolder + " does not exist.", getRascalMfLocation(rascalProject))); + } - var srcFolder = URIUtil.getChildLocation(manifestRoot, srcName); - - if (!reg.exists(srcFolder) || !reg.isDirectory(srcFolder)) { - messages.append(Messages.error("Source folder " + srcFolder + " does not exist.", getRascalMfLocation(rascalProject))); + srcsWriter.append(srcFolder); } - - srcsWriter.append(srcFolder); } return new PathConfig( @@ -684,6 +664,65 @@ else if (rascalProject != null) { messages.done()); } + /** + * Adds the source folders of the `rascal` project to `srcsWriter`. + * + * For each source folder, there are at most two version to choose from: + * - The version in the "current" `rascal` (as per + * `resolveCurrentRascalRuntimeJar()`). Alway available. + * - The version in the "other" `rascal` (as per the + * `URIResolverRegistry`). Available when `rascal` itself is the main + * project, or when `rascal` is open in the workspace. + * + * The version of each source folder of the `rascal` project to add, is + * chosen based on the kind of that source folder: + * - Kind #1 (e.g., `.../library`, i.e., `|std:///|`): Add the version of + * the source folder in the current `rascal` + * - Kind #2 (e.g., `.../typepal`): Add the version of the source folder + * in the other `rascal` (if available) or the current `rascal` (else) + * - Kind #3 (e.g., `test/...`): Add the version of the source folder in + * the other `rascal` (if available) + * + * Thus, source folders of kinds #1 and #2 are added always, while source + * folders of kind #3 are added only when the `rascal` project itself is + * being developed. + * + * @throws IOException When the current `rascal` can't be resolved + */ + private static void addRascalToSourcePath(IListWriter srcsWriter) throws IOException { + var currentRascalTargetClasses = JarURIResolver.jarify(resolveCurrentRascalRuntimeJar()); + + // Assumption: If `rascal` itself is the main project, or if `rascal` is + // open in the workspace, then its root folder has already been + // registered as `|project://rascal/|` in the resolver registry (so + // checking the project name isn't needed after checking the registry). + var otherRascal = URIUtil.correctLocation("project", "rascal", ""); + var otherRascalExists = URIResolverRegistry.getInstance().exists(otherRascal); + + // Include source folders of kind #1 + srcsWriter.append(URIUtil.rootLocation("std")); + + // Include source folders of kind #2 + if (otherRascalExists) { + srcsWriter.append(URIUtil.getChildLocation(otherRascal, "src/org/rascalmpl/typepal")); + } else { + srcsWriter.append(URIUtil.getChildLocation(currentRascalTargetClasses, "org/rascalmpl/typepal")); + } + + // Include source folders of kind #3 + if (otherRascalExists) { + Predicate isKind3 = s -> + !s.equals("src/org/rascalmpl/library") && + !s.equals("src/org/rascalmpl/typepal"); + + new RascalManifest() + .getSourceRoots(otherRascal) + .stream() + .filter(isKind3) + .forEach(src -> srcsWriter.append(URIUtil.getChildLocation(otherRascal, src))); + } + } + private static void addLibraryToSourcePath(URIResolverRegistry reg, IListWriter srcsWriter, IListWriter messages, ISourceLocation jar) { if (!reg.exists(URIUtil.getChildLocation(jar, RascalManifest.META_INF_RASCAL_MF))) { // skip all the non Rascal libraries @@ -820,7 +859,7 @@ public void printInterpreterConfigurationStatus(PrintWriter out) { getSrcs().forEach(f -> { var l = (ISourceLocation) f; var s = " ".repeat(4) + l; - if (l.getScheme().equals("std")) { + if (l.getScheme().equals("std") || l.getScheme().equals("project")) { try { s += " at " + URIResolverRegistry.getInstance().logicalToPhysical(l); } catch (IOException e) { From f45a88511c1d38ee09760b005c138d3e1fa56b45 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 27 Jan 2025 17:00:34 +0100 Subject: [PATCH 50/66] Add `compiler` and `typepal` folders to RASCAL.MF and pom.xml --- META-INF/RASCAL.MF | 2 +- pom.xml | 2 ++ src/org/rascalmpl/compiler/Compiler.rsc | 4 ++++ src/org/rascalmpl/typepal/Typepal.rsc | 3 +-- 4 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 src/org/rascalmpl/compiler/Compiler.rsc diff --git a/META-INF/RASCAL.MF b/META-INF/RASCAL.MF index c43531825ba..3fe8b99bed5 100644 --- a/META-INF/RASCAL.MF +++ b/META-INF/RASCAL.MF @@ -1,5 +1,5 @@ Project-Name: rascal -Source: src/org/rascalmpl/library,src/org/rascalmpl/typepal,test/org/rascalmpl/benchmark,test//org/rascalmpl/test/data +Source: src/org/rascalmpl/library,src/org/rascalmpl/compiler,src/org/rascalmpl/typepal,test/org/rascalmpl/benchmark,test//org/rascalmpl/test/data Courses: src/org/rascalmpl/courses diff --git a/pom.xml b/pom.xml index 661feb3bc04..020b8ad7c11 100644 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,8 @@ ${project.build.outputDirectory} ${project.basedir}/src/org/rascalmpl/library + ${project.basedir}/src/org/rascalmpl/compiler + ${project.basedir}/src/org/rascalmpl/typepal |std:///| ${project.basedir}/FUNDING diff --git a/src/org/rascalmpl/compiler/Compiler.rsc b/src/org/rascalmpl/compiler/Compiler.rsc new file mode 100644 index 00000000000..14d0e83141e --- /dev/null +++ b/src/org/rascalmpl/compiler/Compiler.rsc @@ -0,0 +1,4 @@ +module Compiler + +// TODO: This is intended to be a temporary placeholder module (useful for +// testing `PathConfig` changes). It should be removed after the merge. diff --git a/src/org/rascalmpl/typepal/Typepal.rsc b/src/org/rascalmpl/typepal/Typepal.rsc index 12676023bcd..ff80d078e57 100644 --- a/src/org/rascalmpl/typepal/Typepal.rsc +++ b/src/org/rascalmpl/typepal/Typepal.rsc @@ -1,5 +1,4 @@ module Typepal // TODO: This is intended to be a temporary placeholder module (useful for -// testing `PathConfig` changes). It should be removed when `typepal` has been -// merged into `rascal`. \ No newline at end of file +// testing `PathConfig` changes). It should be removed after the merge. \ No newline at end of file From 94e4074d1e317d92fa0c05f4f09222c48d656eff Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 27 Jan 2025 17:02:47 +0100 Subject: [PATCH 51/66] Refactor `ShellEvaluatorFactory` to ensure that *only* the path config determines the content of the search path --- .../shell/ShellEvaluatorFactory.java | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java index 095bc7705b9..5985c967dc9 100644 --- a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java +++ b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java @@ -28,34 +28,30 @@ public class ShellEvaluatorFactory { public static Evaluator getDefaultEvaluator(InputStream input, OutputStream stdout, OutputStream stderr, IRascalMonitor monitor) { - GlobalEnvironment heap = new GlobalEnvironment(); - ModuleEnvironment root = heap.addModule(new ModuleEnvironment(ModuleEnvironment.SHELL_MODULE, heap)); - IValueFactory vf = ValueFactoryFactory.getValueFactory(); - Evaluator evaluator = new Evaluator(vf, input, stderr, stdout, root, heap, monitor); - evaluator.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); - + ISourceLocation rootFolder = null; URIResolverRegistry reg = URIResolverRegistry.getInstance(); - if (!reg.getRegisteredInputSchemes().contains("project") && !reg.getRegisteredLogicalSchemes().contains("project")) { - ISourceLocation rootFolder = inferProjectRoot(new File(System.getProperty("user.dir"))); - if (rootFolder != null) { - configureProjectEvaluator(evaluator, rootFolder); - } + rootFolder = inferProjectRoot(new File(System.getProperty("user.dir"))); } - return evaluator; + return createEvaluator(input, stdout, stderr, monitor, rootFolder); } public static Evaluator getDefaultEvaluatorForLocation(File fileOrFolderInProject, InputStream input, OutputStream stdout, OutputStream stderr, IRascalMonitor monitor) { + ISourceLocation rootFolder = inferProjectRoot(fileOrFolderInProject); + return createEvaluator(input, stdout, stderr, monitor, rootFolder); + } + + private static Evaluator createEvaluator(InputStream input, OutputStream stdout, OutputStream stderr, IRascalMonitor monitor, ISourceLocation rootFolder) { GlobalEnvironment heap = new GlobalEnvironment(); ModuleEnvironment root = heap.addModule(new ModuleEnvironment(ModuleEnvironment.SHELL_MODULE, heap)); IValueFactory vf = ValueFactoryFactory.getValueFactory(); Evaluator evaluator = new Evaluator(vf, input, stderr, stdout, root, heap, monitor); - evaluator.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); - ISourceLocation rootFolder = inferProjectRoot(fileOrFolderInProject); if (rootFolder != null) { configureProjectEvaluator(evaluator, rootFolder); + } else { + evaluator.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); } return evaluator; @@ -74,9 +70,6 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio evaluator.addRascalSearchPath((ISourceLocation) path); } - for (IValue path : pcfg.getLibs()) { - evaluator.addRascalSearchPath((ISourceLocation) path); - } ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); evaluator.addClassLoader(cl); From 80ad94ee2e22c4aca9b577d9284041f48a7fe6e3 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 27 Jan 2025 17:30:55 +0100 Subject: [PATCH 52/66] Reimplement method to add the standard library, compiler, and Typepal to the source path according to latest approach --- .../rascalmpl/library/util/PathConfig.java | 90 +++++++++---------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 2e2b87d5301..ccefd7eaa0f 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -638,7 +638,7 @@ else if (rascalProject != null) { } try { - addRascalToSourcePath(srcsWriter); + addRascalToSourcePath(projectName, srcsWriter); } catch (IOException e) { messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); } @@ -665,61 +665,55 @@ else if (rascalProject != null) { } /** - * Adds the source folders of the `rascal` project to `srcsWriter`. + * Adds the standard library to `srcsWriter`. If the path config's project + * is `rascal` or `rascal-lsp` (as indicated by `projectName`), then adds + * the Rascal compiler and Typepal as well. * - * For each source folder, there are at most two version to choose from: - * - The version in the "current" `rascal` (as per - * `resolveCurrentRascalRuntimeJar()`). Alway available. - * - The version in the "other" `rascal` (as per the - * `URIResolverRegistry`). Available when `rascal` itself is the main - * project, or when `rascal` is open in the workspace. - * - * The version of each source folder of the `rascal` project to add, is - * chosen based on the kind of that source folder: - * - Kind #1 (e.g., `.../library`, i.e., `|std:///|`): Add the version of - * the source folder in the current `rascal` - * - Kind #2 (e.g., `.../typepal`): Add the version of the source folder - * in the other `rascal` (if available) or the current `rascal` (else) - * - Kind #3 (e.g., `test/...`): Add the version of the source folder in - * the other `rascal` (if available) - * - * Thus, source folders of kinds #1 and #2 are added always, while source - * folders of kind #3 are added only when the `rascal` project itself is - * being developed. + * More precisely, the following rules are applied: + * - Always load `|std:///|` from the "current" `rascal` (as per + * `resolveCurrentRascalRuntimeJar()`) + * - If the path config's project is `rascal`, then: + * - If `|project://rascal/|` and `|project://typepal/|` exists, do + * load the compiler and Typepal from the corresponding open folders + * in the workspace. + * - Else, don't load the compiler and Typepal. + * - If the path config's project is `rascal-lsp`: + * - If `|project://rascal/|` and `|project://typepal/|` exists, do + * load the compiler and Typepal from the corresponding open folders + * in the workspace. + * - Else, do load the compiler and Typepal from the current `rascal`. * * @throws IOException When the current `rascal` can't be resolved */ - private static void addRascalToSourcePath(IListWriter srcsWriter) throws IOException { - var currentRascalTargetClasses = JarURIResolver.jarify(resolveCurrentRascalRuntimeJar()); - - // Assumption: If `rascal` itself is the main project, or if `rascal` is - // open in the workspace, then its root folder has already been - // registered as `|project://rascal/|` in the resolver registry (so - // checking the project name isn't needed after checking the registry). - var otherRascal = URIUtil.correctLocation("project", "rascal", ""); - var otherRascalExists = URIResolverRegistry.getInstance().exists(otherRascal); + private static void addRascalToSourcePath(String projectName, IListWriter srcsWriter) throws IOException { - // Include source folders of kind #1 + // General case srcsWriter.append(URIUtil.rootLocation("std")); - // Include source folders of kind #2 - if (otherRascalExists) { - srcsWriter.append(URIUtil.getChildLocation(otherRascal, "src/org/rascalmpl/typepal")); - } else { - srcsWriter.append(URIUtil.getChildLocation(currentRascalTargetClasses, "org/rascalmpl/typepal")); - } + // Special cases + if (projectName.equals("rascal") || projectName.equals("rascal-lsp")) { + var currentRascalTargetClasses = JarURIResolver.jarify(resolveCurrentRascalRuntimeJar()); + + var workspaceRascal = URIUtil.correctLocation("project", "rascal", ""); + var workspaceRascalExists = URIResolverRegistry.getInstance().exists(workspaceRascal); + var workspaceTypepal = URIUtil.correctLocation("project", "typepal", ""); + var workspaceTypepalExists = URIResolverRegistry.getInstance().exists(workspaceTypepal); + + // Special case: If the path config's project is `rascal` or + // `rascal-lsp`, and `rascal` and `typepal` are in the workspace, + // then use those open folders + if (workspaceRascalExists && workspaceTypepalExists) { + srcsWriter.append(URIUtil.getChildLocation(workspaceRascal, "src/org/rascalmpl/compiler")); + srcsWriter.append(URIUtil.getChildLocation(workspaceTypepal, "src")); + } - // Include source folders of kind #3 - if (otherRascalExists) { - Predicate isKind3 = s -> - !s.equals("src/org/rascalmpl/library") && - !s.equals("src/org/rascalmpl/typepal"); - - new RascalManifest() - .getSourceRoots(otherRascal) - .stream() - .filter(isKind3) - .forEach(src -> srcsWriter.append(URIUtil.getChildLocation(otherRascal, src))); + // Special case: If the path config's project is `rascal-lsp`, and + // `rascal` or `typepal` isn't open in the workspce, then use the + // "current" `rascal` + else if (projectName.equals("rascal-lsp")) { + srcsWriter.append(URIUtil.getChildLocation(currentRascalTargetClasses, "org/rascalmpl/compiler")); + srcsWriter.append(URIUtil.getChildLocation(currentRascalTargetClasses, "org/rascalmpl/typepal")); + } } } From d328b34e6e125146369ef8f5ed94421ce6e7c34d Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Wed, 29 Jan 2025 15:57:43 +0100 Subject: [PATCH 53/66] Update code to load TypePal from a deployed jar (instead of a copy inside the "current" `rascal`, which won't exist) --- META-INF/RASCAL.MF | 2 +- .../rascalmpl/library/util/PathConfig.java | 27 ++++++++++--------- src/org/rascalmpl/typepal/Typepal.rsc | 4 --- 3 files changed, 16 insertions(+), 17 deletions(-) delete mode 100644 src/org/rascalmpl/typepal/Typepal.rsc diff --git a/META-INF/RASCAL.MF b/META-INF/RASCAL.MF index 3fe8b99bed5..e0e93a150b1 100644 --- a/META-INF/RASCAL.MF +++ b/META-INF/RASCAL.MF @@ -1,5 +1,5 @@ Project-Name: rascal -Source: src/org/rascalmpl/library,src/org/rascalmpl/compiler,src/org/rascalmpl/typepal,test/org/rascalmpl/benchmark,test//org/rascalmpl/test/data +Source: src/org/rascalmpl/library,src/org/rascalmpl/compiler,test/org/rascalmpl/benchmark,test//org/rascalmpl/test/data Courses: src/org/rascalmpl/courses diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index ccefd7eaa0f..7598fbe0a11 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -667,23 +667,26 @@ else if (rascalProject != null) { /** * Adds the standard library to `srcsWriter`. If the path config's project * is `rascal` or `rascal-lsp` (as indicated by `projectName`), then adds - * the Rascal compiler and Typepal as well. + * the compiler and TypePal as well. * * More precisely, the following rules are applied: * - Always load `|std:///|` from the "current" `rascal` (as per * `resolveCurrentRascalRuntimeJar()`) * - If the path config's project is `rascal`, then: * - If `|project://rascal/|` and `|project://typepal/|` exists, do - * load the compiler and Typepal from the corresponding open folders + * load the compiler and TypePal from the corresponding open folders * in the workspace. - * - Else, don't load the compiler and Typepal. + * - Else, don't load the compiler and TypePal. * - If the path config's project is `rascal-lsp`: * - If `|project://rascal/|` and `|project://typepal/|` exists, do - * load the compiler and Typepal from the corresponding open folders + * load the compiler and TypePal from the corresponding open folders * in the workspace. - * - Else, do load the compiler and Typepal from the current `rascal`. + * - Else, do load the compiler and TypePal from the current `rascal` + * and the TypePal jar on the class path. * - * @throws IOException When the current `rascal` can't be resolved + * @throws IOException When the path config's project is `rascal-lsp`, but + * one of the following is the case: (a) the current `rascal` can't be + * resolved; (b) the TypePal jar isn't on the class path. */ private static void addRascalToSourcePath(String projectName, IListWriter srcsWriter) throws IOException { @@ -692,8 +695,6 @@ private static void addRascalToSourcePath(String projectName, IListWriter srcsWr // Special cases if (projectName.equals("rascal") || projectName.equals("rascal-lsp")) { - var currentRascalTargetClasses = JarURIResolver.jarify(resolveCurrentRascalRuntimeJar()); - var workspaceRascal = URIUtil.correctLocation("project", "rascal", ""); var workspaceRascalExists = URIResolverRegistry.getInstance().exists(workspaceRascal); var workspaceTypepal = URIUtil.correctLocation("project", "typepal", ""); @@ -708,11 +709,13 @@ private static void addRascalToSourcePath(String projectName, IListWriter srcsWr } // Special case: If the path config's project is `rascal-lsp`, and - // `rascal` or `typepal` isn't open in the workspce, then use the - // "current" `rascal` + // `rascal` or `typepal` isn't open in the workspace, then use the + // current `rascal` and the TypePal jar on the class path else if (projectName.equals("rascal-lsp")) { - srcsWriter.append(URIUtil.getChildLocation(currentRascalTargetClasses, "org/rascalmpl/compiler")); - srcsWriter.append(URIUtil.getChildLocation(currentRascalTargetClasses, "org/rascalmpl/typepal")); + var deployedRascal = JarURIResolver.jarify(resolveCurrentRascalRuntimeJar()); + var deployedTypepal = JarURIResolver.jarify(PathConfig.resolveProjectOnClasspath("typepal")); + srcsWriter.append(URIUtil.getChildLocation(deployedRascal, "org/rascalmpl/compiler")); + srcsWriter.append(URIUtil.getChildLocation(deployedTypepal, "src")); } } } diff --git a/src/org/rascalmpl/typepal/Typepal.rsc b/src/org/rascalmpl/typepal/Typepal.rsc deleted file mode 100644 index ff80d078e57..00000000000 --- a/src/org/rascalmpl/typepal/Typepal.rsc +++ /dev/null @@ -1,4 +0,0 @@ -module Typepal - -// TODO: This is intended to be a temporary placeholder module (useful for -// testing `PathConfig` changes). It should be removed after the merge. \ No newline at end of file From 4d9e2f9d7848816958a49796a97209662cbd1c17 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Wed, 29 Jan 2025 16:03:53 +0100 Subject: [PATCH 54/66] Update pom.xml --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 020b8ad7c11..402e3bc5443 100644 --- a/pom.xml +++ b/pom.xml @@ -136,7 +136,6 @@ ${project.basedir}/src/org/rascalmpl/library ${project.basedir}/src/org/rascalmpl/compiler - ${project.basedir}/src/org/rascalmpl/typepal |std:///| ${project.basedir}/FUNDING From 19ff3fd7045ac709ee3fa4b7273405a76e23c9cf Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Wed, 29 Jan 2025 16:07:13 +0100 Subject: [PATCH 55/66] Remove unused import --- src/org/rascalmpl/library/util/PathConfig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 7598fbe0a11..a86df7f0935 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -18,7 +18,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Predicate; import java.util.jar.Manifest; import org.rascalmpl.interpreter.Configuration; From 6b88e99fc3cc914be570093a522433776ed0979c Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 6 Feb 2025 12:26:36 +0100 Subject: [PATCH 56/66] fixed broken merge --- .../rascalmpl/library/util/PathConfig.java | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 10e5df68d3e..a03d01d3b30 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -1,9 +1,11 @@ package org.rascalmpl.library.util; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; @@ -16,7 +18,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.jar.Manifest; import org.rascalmpl.interpreter.Configuration; @@ -43,33 +44,34 @@ import io.usethesource.vallang.type.TypeStore; public class PathConfig { - - private static final IValueFactory vf = ValueFactoryFactory.getValueFactory(); - private final TypeFactory tf = TypeFactory.getInstance(); - private final TypeStore store = new TypeStore(); - - // WARNING: these definitions must reflect the definitions in util::Reflective.rsc - private final Type PathConfigType = tf.abstractDataType(store, "PathConfig"); - private final Type pathConfigConstructor = tf.constructor(store, PathConfigType, "pathConfig"); - - private final List srcs; // List of locations to search for source files - private final List libs; // List of (library) locations to search for derived files - private final List ignores; // List of (library) locations to ignore while compiling - private final List javaCompilerPath; // List of (library) locations to use for the compiler path of generated parsers - private final List classloaders; // List of (library) locations to use to bootstrap classloaders from - - private final ISourceLocation bin; // Global location for derived files outside projects or libraries - - private static ISourceLocation defaultStd; - private static List defaultIgnores; - private static List defaultJavaCompilerPath; - private static List defaultClassloaders; - private static ISourceLocation defaultBin; - + private static final IValueFactory vf = ValueFactoryFactory.getValueFactory(); + private final TypeFactory tf = TypeFactory.getInstance(); + private final TypeStore store = new TypeStore(); + + // WARNING: these definitions must reflect the definitions in `util::Reflective` + private final Type PathConfigType = tf.abstractDataType(store, "PathConfig"); + private final Type pathConfigConstructor = tf.constructor(store, PathConfigType, "pathConfig"); + + private final List srcs; + private final List libs; + private final ISourceLocation bin; + private final List ignores; + private final ISourceLocation generatedSources; + private final List messages; + + + // defaults are shared here because they occur in different use places. + private static final List defaultIgnores = Collections.emptyList(); + private static final ISourceLocation defaultGeneratedSources = URIUtil.unknownLocation(); + private static final List defaultMessages = Collections.emptyList(); + private static final ISourceLocation defaultBin = URIUtil.unknownLocation(); + private static final List defaultLibs = Collections.emptyList(); + + /** implementation detail of communicating with the `mvn` command */ private static final String WINDOWS_ROOT_TRUSTSTORE_TYPE_DEFINITION = "-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT"; - public static enum RascalConfigMode { - INTERPETER, + public static enum RascalConfigMode { + INTERPRETER, COMPILER } @@ -361,9 +363,8 @@ public static ISourceLocation resolveProjectOnClasspath(String projectName) thro loc = vf.sourceLocation(URIUtil.fromURL(url)); loc = URIUtil.getParentLocation(URIUtil.getParentLocation(loc)); } - - - return loc; + + return MavenRepositoryURIResolver.mavenize(loc); } } catch (IOException | URISyntaxException e) { @@ -477,7 +478,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes libsWriter.append(resolveCurrentRascalRuntimeJar()); } catch (IOException e) { - messages.append(Messages.error(e.getMessage(), manifestRoot)); + messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); } } @@ -490,7 +491,7 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes ISourceLocation rascalProject = null; try { - IList mavenClasspath = getPomXmlCompilerClasspath(manifestRoot, messages); + IList mavenClasspath = getPomXmlCompilerClasspath(manifestRoot); // This processes Rascal libraries we can find in maven dependencies, // adding them to libs or srcs depending on which mode we are in; interpreted or compiled. @@ -636,7 +637,8 @@ else if (rascalProject != null) { try { addRascalToSourcePath(projectName, srcsWriter); - } catch (IOException e) { + } + catch (IOException e) { messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); } @@ -781,9 +783,8 @@ private static ISourceLocation getPomXmlLocation(ISourceLocation project) { * if there is such a file. * @param manifestRoot * @return - * @throws IOException */ - private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot, IListWriter messages) { + private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) { try { String mavenDependencyPlugin = "org.apache.maven.plugins:maven-dependency-plugin:3.8.0"; // First, make sure that maven-dependency-plugin is downloaded when not available @@ -801,7 +802,6 @@ private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot, IL return MavenRepositoryURIResolver.mavenize(URIUtil.createFileLocation(elem)); } catch (URISyntaxException e) { - messages.append(Messages.warning(e.getMessage(), getPomXmlLocation(manifestRoot)); return null; } }) @@ -809,7 +809,6 @@ private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot, IL .collect(vf.listWriter()); } catch (IOException | RuntimeException e) { - messages.append(Messages.warning(e.getMessage(), getPomXmlLocation(manifestRoot))); return vf.list(); } } From 57cc181a9c29fe501c820383ec3583a894317698 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 6 Feb 2025 12:56:20 +0100 Subject: [PATCH 57/66] finished a complex merge operation --- pom.xml | 3 -- .../rascalmpl/library/util/PathConfig.java | 7 +-- .../shell/ShellEvaluatorFactory.java | 48 ++++++------------- .../tutor/repl/TutorCommandExecutor.java | 42 +++++++++------- 4 files changed, 42 insertions(+), 58 deletions(-) diff --git a/pom.xml b/pom.xml index ace803463b5..9e3fdb822d6 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,6 @@ UTF-8 - 7.5.0 3.9.9 org.rascalmpl.shell.RascalShell 3 @@ -576,7 +575,5 @@ - - diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index a03d01d3b30..c9d0c26b8cb 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -67,9 +67,6 @@ public class PathConfig { private static final ISourceLocation defaultBin = URIUtil.unknownLocation(); private static final List defaultLibs = Collections.emptyList(); - /** implementation detail of communicating with the `mvn` command */ - private static final String WINDOWS_ROOT_TRUSTSTORE_TYPE_DEFINITION = "-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT"; - public static enum RascalConfigMode { INTERPRETER, COMPILER @@ -379,7 +376,7 @@ public static ISourceLocation resolveCurrentRascalRuntimeJar() throws IOExceptio return resolveProjectOnClasspath("rascal"); } - private static ISourceLocation inferProjectRoot(ISourceLocation member) { + public static ISourceLocation inferProjectRoot(ISourceLocation member) { ISourceLocation current = member; URIResolverRegistry reg = URIResolverRegistry.getInstance(); while (current != null && reg.exists(current) && reg.isDirectory(current)) { @@ -805,7 +802,7 @@ private static IList getPomXmlCompilerClasspath(ISourceLocation manifestRoot) { return null; } }) - .filter(Objects::nonNull) + .filter(x -> x != null) // Objects.nonNull is probably from a higher java version? .collect(vf.listWriter()); } catch (IOException | RuntimeException e) { diff --git a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java index be411e54e75..493ad4caa74 100644 --- a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java +++ b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java @@ -1,7 +1,6 @@ package org.rascalmpl.shell; import java.io.File; -import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.net.URISyntaxException; @@ -36,11 +35,15 @@ public static Evaluator getDefaultEvaluator(Reader input, PrintWriter stdout, Pr evaluator.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); URIResolverRegistry reg = URIResolverRegistry.getInstance(); + if (!reg.getRegisteredInputSchemes().contains("project") && !reg.getRegisteredLogicalSchemes().contains("project")) { - rootFolder = inferProjectRoot(new File(System.getProperty("user.dir"))); + ISourceLocation rootFolder = PathConfig.inferProjectRoot(URIUtil.rootLocation("cwd")); + if (rootFolder != null) { + configureProjectEvaluator(evaluator, rootFolder); + } } - return createEvaluator(input, stdout, stderr, monitor, rootFolder); + return evaluator; } public static Evaluator getDefaultEvaluatorForLocation(File fileOrFolderInProject, Reader input, PrintWriter stdout, PrintWriter stderr, IRascalMonitor monitor) { @@ -48,11 +51,16 @@ public static Evaluator getDefaultEvaluatorForLocation(File fileOrFolderInProjec ModuleEnvironment root = heap.addModule(new ModuleEnvironment(ModuleEnvironment.SHELL_MODULE, heap)); IValueFactory vf = ValueFactoryFactory.getValueFactory(); Evaluator evaluator = new Evaluator(vf, input, stderr, stdout, root, heap, monitor); + evaluator.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); - if (rootFolder != null) { - configureProjectEvaluator(evaluator, rootFolder); - } else { - evaluator.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); + try { + ISourceLocation rootFolder = PathConfig.inferProjectRoot(URIUtil.createFileLocation(fileOrFolderInProject.toString())); + if (rootFolder != null) { + configureProjectEvaluator(evaluator, rootFolder); + } + } + catch (URISyntaxException e) { + e.printStackTrace(stderr); } return evaluator; @@ -71,35 +79,9 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio evaluator.addRascalSearchPath((ISourceLocation) path); } - ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); evaluator.addClassLoader(cl); Messages.write(pcfg.getMessages(), evaluator.getOutPrinter()); } - - /** - * Searchers for META-INF/RASCAL.MF to infer the root of a Rascal source project. - * If cwd has a parent which contains this META-INF/RASCAL.MF file then the - * location of this parent is returned. If it is not found, this function returns null. - * @param cwd - * @return - */ - public static ISourceLocation inferProjectRoot(File cwd) { - try { - File current = cwd; - while (current != null && current.exists() && current.isDirectory()) { - if (new File(current, "META-INF/RASCAL.MF").exists()) { - return URIUtil.createFileLocation(current.getAbsolutePath()); - } - current = current.getParentFile(); - } - } - catch (URISyntaxException e) { - return null; - } - - return null; - } - } diff --git a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java index a18893c7499..ecfc6977895 100644 --- a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java +++ b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java @@ -57,24 +57,35 @@ public TutorCommandExecutor(PathConfig pcfg) throws IOException, URISyntaxExcept protected Evaluator buildEvaluator(Reader input, PrintWriter stdout, PrintWriter stderr, IDEServices services) { var eval = super.buildEvaluator(input, stdout, stderr, services); - eval.getConfiguration().setRascalJavaClassPathProperty(javaCompilerPathAsString(pcfg.getJavaCompilerPath())); - ISourceLocation projectRoot = inferProjectRoot((ISourceLocation) pcfg.getSrcs().get(0)); - String projectName = new RascalManifest().getProjectName(projectRoot); - URIResolverRegistry reg = URIResolverRegistry.getInstance(); - reg.registerLogical(new ProjectURIResolver(projectRoot, projectName)); - reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); + try { + eval.getConfiguration().setRascalJavaClassPathProperty(PathConfig.resolveCurrentRascalRuntimeJar().getPath()); + } + catch (IOException e) { + services.warning(e.getMessage(), URIUtil.rootLocation("unknown")); + } + + if (!pcfg.getSrcs().isEmpty()) { + ISourceLocation projectRoot = inferProjectRoot((ISourceLocation) pcfg.getSrcs().get(0)); + String projectName = new RascalManifest().getProjectName(projectRoot); + URIResolverRegistry reg = URIResolverRegistry.getInstance(); + reg.registerLogical(new ProjectURIResolver(projectRoot, projectName)); + reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); - for (IValue path : pcfg.getSrcs()) { - eval.addRascalSearchPath((ISourceLocation) path); + for (IValue path : pcfg.getSrcs()) { + eval.addRascalSearchPath((ISourceLocation) path); + } + + for (IValue path : pcfg.getLibs()) { + eval.addRascalSearchPath((ISourceLocation) path); + } + + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); + eval.addClassLoader(cl); } - - for (IValue path : pcfg.getLibs()) { - eval.addRascalSearchPath((ISourceLocation) path); + else { + services.warning("No src path configured for tutor", URIUtil.rootLocation("unknown")); } - - ClassLoader cl = new SourceLocationClassLoader(pcfg.getClassloaders(), ShellEvaluatorFactory.class.getClassLoader()); - eval.addClassLoader(cl); return eval; } @@ -83,7 +94,6 @@ protected Evaluator buildEvaluator(Reader input, PrintWriter stdout, PrintWriter protected IDEServices buildIDEService(PrintWriter err, IRascalMonitor monitor, Terminal term) { return (monitor instanceof IDEServices) ? (IDEServices)monitor : new TutorIDEServices(err); } - }; var terminal = TerminalBuilder.builder() @@ -94,8 +104,6 @@ protected IDEServices buildIDEService(PrintWriter err, IRascalMonitor monitor, T .encoding(StandardCharsets.UTF_8) .build(); - - interpreter.initialize(Reader.nullReader(), outPrinter, errPrinter, new TutorIDEServices(errPrinter), terminal); screenshot = loadScreenShotter(); } From 04a07a8ff43d01b443bf87d6334262c2812a521c Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 6 Feb 2025 12:56:49 +0100 Subject: [PATCH 58/66] minor layout --- .../tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java index ecfc6977895..9dafad3e294 100644 --- a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java +++ b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java @@ -54,8 +54,7 @@ public class TutorCommandExecutor { public TutorCommandExecutor(PathConfig pcfg) throws IOException, URISyntaxException{ interpreter = new RascalInterpreterREPL() { @Override - protected Evaluator buildEvaluator(Reader input, PrintWriter stdout, PrintWriter stderr, - IDEServices services) { + protected Evaluator buildEvaluator(Reader input, PrintWriter stdout, PrintWriter stderr, IDEServices services) { var eval = super.buildEvaluator(input, stdout, stderr, services); try { From 30f7ece8b026717fc0ae14bb6ee905ea8e833399 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 6 Feb 2025 12:58:35 +0100 Subject: [PATCH 59/66] fixed a nasty npe --- .../tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java index 9dafad3e294..731bf97d23a 100644 --- a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java +++ b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java @@ -165,7 +165,6 @@ private String javaCompilerPathAsString(IList javaCompilerPath) { return b.toString(); } - public void reset() { interpreter.cancelRunningCommandRequested(); interpreter.cleanEnvironment(); @@ -186,7 +185,7 @@ else if (replResult instanceof IImageCommandOutput) { var img = ((IImageCommandOutput)replResult).asImage(); result.put(img.mimeType(), uuencode(img)); } - else if (replResult instanceof IWebContentOutput) { + else if (replResult instanceof IWebContentOutput && screenshot != null) { var webResult = (IWebContentOutput)replResult; try { String pngImage = screenshot.takeScreenshotAsBase64PNG(webResult.webUri().toASCIIString()); From afd75974a9d59d6977c56b6df1a1df759654bdda Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Thu, 6 Feb 2025 13:03:06 +0100 Subject: [PATCH 60/66] strange method got lost in unrelated file URIUtil --- src/org/rascalmpl/uri/URIUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/org/rascalmpl/uri/URIUtil.java b/src/org/rascalmpl/uri/URIUtil.java index a1aee9a8e07..c44b6d76749 100644 --- a/src/org/rascalmpl/uri/URIUtil.java +++ b/src/org/rascalmpl/uri/URIUtil.java @@ -487,4 +487,8 @@ else if (index != -1) { return URIUtil.changePath(location, path); } + + public static URI invalidURI() { + return rootScheme("invalid"); + } } From f495574c55c2f3a1856ac8533c595c795605bdac Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 7 Feb 2025 23:10:13 +0100 Subject: [PATCH 61/66] some cleanup and factored out the shared monitor for testing in its own class to avoid cyclic static block dependencies --- src/org/rascalmpl/interpreter/Evaluator.java | 5 +-- .../interpreter/IEvaluatorContext.java | 1 - .../rascalmpl/library/util/PathConfig.java | 4 +- .../rascalmpl/library/util/Reflective.java | 2 - src/org/rascalmpl/repl/StopREPLException.java | 1 + .../repl/rascal/RascalLineParser.java | 1 - ...ascalJUnitParallelRecursiveTestRunner.java | 4 +- .../infrastructure/RascalJUnitTestRunner.java | 23 +---------- .../RascalJunitConsoleMonitor.java | 38 +++++++++++++++++++ .../test/infrastructure/TestFramework.java | 2 +- .../tutor/repl/TutorCommandExecutor.java | 25 ------------ .../rascalmpl/uri/URIResolverRegistry.java | 1 + .../uri/file/MavenRepositoryURIResolver.java | 9 +++-- test/org/rascalmpl/MatchFingerprintTest.java | 5 ++- 14 files changed, 56 insertions(+), 65 deletions(-) create mode 100644 src/org/rascalmpl/test/infrastructure/RascalJunitConsoleMonitor.java diff --git a/src/org/rascalmpl/interpreter/Evaluator.java b/src/org/rascalmpl/interpreter/Evaluator.java index 96892423acc..f55dcf8785c 100755 --- a/src/org/rascalmpl/interpreter/Evaluator.java +++ b/src/org/rascalmpl/interpreter/Evaluator.java @@ -37,7 +37,6 @@ import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; -import java.util.SortedSet; import java.util.Stack; import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -264,10 +263,10 @@ public Evaluator(IValueFactory vf, Reader input, PrintWriter stderr, PrintWriter updateProperties(); if (stderr == null) { - throw new NullPointerException(); + throw new NullPointerException("stderr is null"); } if (stdout == null) { - throw new NullPointerException(); + throw new NullPointerException("stdout is null"); } // default event trigger to swallow events diff --git a/src/org/rascalmpl/interpreter/IEvaluatorContext.java b/src/org/rascalmpl/interpreter/IEvaluatorContext.java index 4cb527af3f3..bbfb4bf6494 100644 --- a/src/org/rascalmpl/interpreter/IEvaluatorContext.java +++ b/src/org/rascalmpl/interpreter/IEvaluatorContext.java @@ -19,7 +19,6 @@ import java.io.PrintWriter; import java.io.Reader; -import java.util.Collection; import java.util.Map; import java.util.Stack; diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index c9d0c26b8cb..e299701d671 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -1,12 +1,9 @@ package org.rascalmpl.library.util; -import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.net.URISyntaxException; @@ -359,6 +356,7 @@ public static ISourceLocation resolveProjectOnClasspath(String projectName) thro // this is typically a target folder loc = vf.sourceLocation(URIUtil.fromURL(url)); loc = URIUtil.getParentLocation(URIUtil.getParentLocation(loc)); + System.err.println("Found target location for: " + projectName); } return MavenRepositoryURIResolver.mavenize(loc); diff --git a/src/org/rascalmpl/library/util/Reflective.java b/src/org/rascalmpl/library/util/Reflective.java index bc58780afb9..4421ea08a38 100644 --- a/src/org/rascalmpl/library/util/Reflective.java +++ b/src/org/rascalmpl/library/util/Reflective.java @@ -13,10 +13,8 @@ *******************************************************************************/ package org.rascalmpl.library.util; -import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; diff --git a/src/org/rascalmpl/repl/StopREPLException.java b/src/org/rascalmpl/repl/StopREPLException.java index 1445a8973b6..bfc3e1462c0 100644 --- a/src/org/rascalmpl/repl/StopREPLException.java +++ b/src/org/rascalmpl/repl/StopREPLException.java @@ -27,5 +27,6 @@ package org.rascalmpl.repl; public class StopREPLException extends Exception { + private static final long serialVersionUID = 2662112695266901199L; } diff --git a/src/org/rascalmpl/repl/rascal/RascalLineParser.java b/src/org/rascalmpl/repl/rascal/RascalLineParser.java index 001da62bc03..77725730d9e 100644 --- a/src/org/rascalmpl/repl/rascal/RascalLineParser.java +++ b/src/org/rascalmpl/repl/rascal/RascalLineParser.java @@ -32,7 +32,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.jline.reader.EOFError; import org.jline.reader.ParsedLine; diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java index f423d1b5745..9bc755bbf4f 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitParallelRecursiveTestRunner.java @@ -174,7 +174,7 @@ private void runTests(RunNotifier notifier) { assert results.isEmpty(); } finally { - RascalJUnitTestRunner.getCommonMonitor().endAllJobs(); + RascalJunitConsoleMonitor.getInstance().endAllJobs(); } } @@ -301,7 +301,7 @@ private void initializeEvaluator() { heap = new GlobalEnvironment(); root = heap.addModule(new ModuleEnvironment("___junit_test___", heap)); - evaluator = new Evaluator(ValueFactoryFactory.getValueFactory(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out, false), root, heap, RascalJUnitTestRunner.getCommonMonitor()); + evaluator = new Evaluator(ValueFactoryFactory.getValueFactory(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out, false), root, heap, RascalJunitConsoleMonitor.getInstance()); stdout = new PrintWriter(evaluator.getOutPrinter()); stderr = new PrintWriter(evaluator.getErrorPrinter()); diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java index cc0cc00b936..202cbd1481b 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java @@ -12,7 +12,6 @@ import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.PrintWriter; import java.io.Reader; import java.lang.annotation.Annotation; @@ -23,13 +22,11 @@ import java.util.List; import java.util.Queue; -import org.jline.terminal.impl.DumbTerminal; import org.junit.runner.Description; import org.junit.runner.Result; import org.junit.runner.Runner; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; -import org.rascalmpl.debug.IRascalMonitor; import org.rascalmpl.interpreter.Evaluator; import org.rascalmpl.interpreter.ITestResultListener; import org.rascalmpl.interpreter.TestEvaluator; @@ -53,24 +50,6 @@ import io.usethesource.vallang.IValue; public class RascalJUnitTestRunner extends Runner { - private static class InstanceHolder { - final static IRascalMonitor monitor; - static { - try { - // jline is to smart, it intersects with junit runners that also interact with the stream - // so instead of that we direct all the messages to stderr, and disable any smart stuff - monitor = IRascalMonitor.buildConsoleMonitor(new DumbTerminal(InputStream.nullInputStream(), System.out)); - } - catch (IOException e1) { - throw new IllegalStateException("Could not create a terminal representation"); - } - } - } - - public static IRascalMonitor getCommonMonitor() { - return InstanceHolder.monitor; - } - private static Evaluator evaluator; private static GlobalEnvironment heap; private static ModuleEnvironment root; @@ -84,7 +63,7 @@ public static IRascalMonitor getCommonMonitor() { try { heap = new GlobalEnvironment(); root = heap.addModule(new ModuleEnvironment("___junit_test___", heap)); - evaluator = new Evaluator(ValueFactoryFactory.getValueFactory(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out, false), root, heap, getCommonMonitor()); + evaluator = new Evaluator(ValueFactoryFactory.getValueFactory(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out, false), root, heap, RascalJunitConsoleMonitor.getInstance()); evaluator.addRascalSearchPathContributor(StandardLibraryContributor.getInstance()); evaluator.getConfiguration().setErrors(true); diff --git a/src/org/rascalmpl/test/infrastructure/RascalJunitConsoleMonitor.java b/src/org/rascalmpl/test/infrastructure/RascalJunitConsoleMonitor.java new file mode 100644 index 00000000000..f12dd1acfa3 --- /dev/null +++ b/src/org/rascalmpl/test/infrastructure/RascalJunitConsoleMonitor.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009-2025 CWI + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + + * * Davy Landman - Davy.Landman@cwi.nl - CWI + * * Jurgen Vinju - Jurgem.Vinju@cwi.nl - CWI +*******************************************************************************/ +package org.rascalmpl.test.infrastructure; + +import org.jline.terminal.impl.DumbTerminal; +import org.rascalmpl.debug.IRascalMonitor; + +import java.io.IOException; +import java.io.InputStream; + +public class RascalJunitConsoleMonitor { + private static class InstanceHolder { + static IRascalMonitor sInstance; + + static { + try { + sInstance = IRascalMonitor.buildConsoleMonitor(new DumbTerminal(InputStream.nullInputStream(), System.out)); + } + catch (IOException e) { + throw new IllegalStateException("Could not create a terminal representation"); + } + } + } + + public static IRascalMonitor getInstance() { + return InstanceHolder.sInstance; + } +} diff --git a/src/org/rascalmpl/test/infrastructure/TestFramework.java b/src/org/rascalmpl/test/infrastructure/TestFramework.java index dae2d75f473..26e507533a1 100644 --- a/src/org/rascalmpl/test/infrastructure/TestFramework.java +++ b/src/org/rascalmpl/test/infrastructure/TestFramework.java @@ -57,7 +57,7 @@ public class TestFramework { heap = new GlobalEnvironment(); root = heap.addModule(new ModuleEnvironment("___test___", heap)); - evaluator = new Evaluator(ValueFactoryFactory.getValueFactory(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out, false), RascalJUnitTestRunner.getCommonMonitor(), root, heap); + evaluator = new Evaluator(ValueFactoryFactory.getValueFactory(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out, false), RascalJunitConsoleMonitor.getInstance(), root, heap); stdout = evaluator.getOutPrinter(); stderr = evaluator.getErrorPrinter(); diff --git a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java index 731bf97d23a..a11cd3a7f16 100644 --- a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java +++ b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java @@ -1,7 +1,6 @@ package org.rascalmpl.tutor.lang.rascal.tutor.repl; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -11,7 +10,6 @@ import java.lang.reflect.InvocationTargetException; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -38,7 +36,6 @@ import org.rascalmpl.uri.project.ProjectURIResolver; import org.rascalmpl.uri.project.TargetURIResolver; -import io.usethesource.vallang.IList; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; import io.usethesource.vallang.io.StandardTextWriter; @@ -143,28 +140,6 @@ private static ISourceLocation inferProjectRoot(ISourceLocation member) { return current; } - private String javaCompilerPathAsString(IList javaCompilerPath) { - StringBuilder b = new StringBuilder(); - - for (IValue elem : javaCompilerPath) { - ISourceLocation loc = (ISourceLocation) elem; - - if (b.length() != 0) { - b.append(File.pathSeparatorChar); - } - - // this is the precondition - assert loc.getScheme().equals("file"); - - // this is robustness in case of experimentation in pom.xml - if ("file".equals(loc.getScheme())) { - b.append(Paths.get(loc.getURI()).toAbsolutePath().toString()); - } - } - - return b.toString(); - } - public void reset() { interpreter.cancelRunningCommandRequested(); interpreter.cleanEnvironment(); diff --git a/src/org/rascalmpl/uri/URIResolverRegistry.java b/src/org/rascalmpl/uri/URIResolverRegistry.java index 4e55fc2d7bc..4ed6d098bca 100644 --- a/src/org/rascalmpl/uri/URIResolverRegistry.java +++ b/src/org/rascalmpl/uri/URIResolverRegistry.java @@ -137,6 +137,7 @@ public Set getRegisteredClassloaderSchemes() { } private Object constructService(String name) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException { + System.err.println("Constructing " + name); Class clazz = Thread.currentThread().getContextClassLoader().loadClass(name); try { diff --git a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java index 7a16ec7d58b..6678a702977 100644 --- a/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java +++ b/src/org/rascalmpl/uri/file/MavenRepositoryURIResolver.java @@ -247,9 +247,12 @@ public static ISourceLocation mavenize(ISourceLocation loc) { boolean isFileInRepo = loc.getScheme().equals("file") && relative.getScheme().equals("relative"); if (isFileInRepo) { - String groupId = URIUtil.getParentLocation(URIUtil.getParentLocation(URIUtil.getParentLocation(relative))).getPath().substring(1).replaceAll("/", "."); - String artifactId = URIUtil.getLocationName(URIUtil.getParentLocation(URIUtil.getParentLocation(relative))); - String version = URIUtil.getLocationName(URIUtil.getParentLocation(relative)); + relative = URIUtil.getParentLocation(relative); + String version = URIUtil.getLocationName(relative); + relative = URIUtil.getParentLocation(relative); + String artifactId = URIUtil.getLocationName(relative); + relative = URIUtil.getParentLocation(relative); + String groupId = relative.getPath().substring(1).replaceAll("/", "."); return make(groupId, artifactId, version, ""); } diff --git a/test/org/rascalmpl/MatchFingerprintTest.java b/test/org/rascalmpl/MatchFingerprintTest.java index e210f36a191..db7dac57adc 100644 --- a/test/org/rascalmpl/MatchFingerprintTest.java +++ b/test/org/rascalmpl/MatchFingerprintTest.java @@ -22,7 +22,8 @@ import org.rascalmpl.interpreter.Evaluator; import org.rascalmpl.interpreter.env.GlobalEnvironment; import org.rascalmpl.interpreter.env.ModuleEnvironment; -import org.rascalmpl.test.infrastructure.RascalJUnitTestRunner; +import org.rascalmpl.test.infrastructure.RascalJunitConsoleMonitor; + import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IInteger; import io.usethesource.vallang.ISourceLocation; @@ -49,7 +50,7 @@ public class MatchFingerprintTest extends TestCase { private final GlobalEnvironment heap = new GlobalEnvironment(); private final ModuleEnvironment root = new ModuleEnvironment("root", heap); - private final Evaluator eval = new Evaluator(IRascalValueFactory.getInstance(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out), root, heap, RascalJUnitTestRunner.getCommonMonitor()); + private final Evaluator eval = new Evaluator(IRascalValueFactory.getInstance(), Reader.nullReader(), new PrintWriter(System.err, true), new PrintWriter(System.out), root, heap, RascalJunitConsoleMonitor.getInstance()); private final RascalFunctionValueFactory VF = eval.getFunctionValueFactory(); private final TypeFactory TF = TypeFactory.getInstance(); From 11441fc03b59ca0a50f145caf7aabc54e075abe6 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 7 Feb 2025 23:22:08 +0100 Subject: [PATCH 62/66] removed cyclic static dependency between the maven repo resolver and the stdlib resolver by removing a call to mavenize. tricky business. --- src/org/rascalmpl/library/util/PathConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index e299701d671..f22d28f1719 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -359,7 +359,7 @@ public static ISourceLocation resolveProjectOnClasspath(String projectName) thro System.err.println("Found target location for: " + projectName); } - return MavenRepositoryURIResolver.mavenize(loc); + return /*MavenRepositoryURIResolver.mavenize(*/loc; } } catch (IOException | URISyntaxException e) { From 62f0d855d18c2871a8ec575572694ab47db0cfc3 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sat, 8 Feb 2025 12:21:27 +0100 Subject: [PATCH 63/66] cleaned up two debug prints --- src/org/rascalmpl/library/util/PathConfig.java | 4 ++-- src/org/rascalmpl/library/util/ToplevelType.java | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index f22d28f1719..7b632c4c7ff 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -356,10 +356,10 @@ public static ISourceLocation resolveProjectOnClasspath(String projectName) thro // this is typically a target folder loc = vf.sourceLocation(URIUtil.fromURL(url)); loc = URIUtil.getParentLocation(URIUtil.getParentLocation(loc)); - System.err.println("Found target location for: " + projectName); } - return /*MavenRepositoryURIResolver.mavenize(*/loc; + // can not mavenize here, that would cause a circular static initializer race. + return loc; } } catch (IOException | URISyntaxException e) { diff --git a/src/org/rascalmpl/library/util/ToplevelType.java b/src/org/rascalmpl/library/util/ToplevelType.java index 9d1de2616bf..983c3c6aafb 100644 --- a/src/org/rascalmpl/library/util/ToplevelType.java +++ b/src/org/rascalmpl/library/util/ToplevelType.java @@ -198,7 +198,6 @@ public static int getToplevelTypeAsInt(Type t){ private static final Integer valueHashCode = "value".hashCode(); public static int getFingerprintNode(INode nd){ - //System.err.println("getFingerprintNode: " + nd.hashCode() + " for " + nd); return nd.hashCode(); } From fa903ab74d9940d95c3449812c1d95f51cfade1e Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sat, 8 Feb 2025 12:24:08 +0100 Subject: [PATCH 64/66] removed another debug print --- src/org/rascalmpl/uri/URIResolverRegistry.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/rascalmpl/uri/URIResolverRegistry.java b/src/org/rascalmpl/uri/URIResolverRegistry.java index 4ed6d098bca..4e55fc2d7bc 100644 --- a/src/org/rascalmpl/uri/URIResolverRegistry.java +++ b/src/org/rascalmpl/uri/URIResolverRegistry.java @@ -137,7 +137,6 @@ public Set getRegisteredClassloaderSchemes() { } private Object constructService(String name) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException { - System.err.println("Constructing " + name); Class clazz = Thread.currentThread().getContextClassLoader().loadClass(name); try { From c264c6257f96ded8f002f14d8e30cfe8a05b4cd3 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sat, 8 Feb 2025 12:29:33 +0100 Subject: [PATCH 65/66] added test import to the test Compiler module --- src/org/rascalmpl/compiler/Compiler.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/org/rascalmpl/compiler/Compiler.rsc b/src/org/rascalmpl/compiler/Compiler.rsc index 14d0e83141e..55ba2dd82bb 100644 --- a/src/org/rascalmpl/compiler/Compiler.rsc +++ b/src/org/rascalmpl/compiler/Compiler.rsc @@ -1,4 +1,6 @@ module Compiler +import analysis::typepal::TypePal; + // TODO: This is intended to be a temporary placeholder module (useful for // testing `PathConfig` changes). It should be removed after the merge. From 7c77df9a15b37769191aa38da37dd761ca574398 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Sun, 9 Feb 2025 19:31:03 +0100 Subject: [PATCH 66/66] generalized commandline version of project and target resolvers to read projects from a common workspace folder, to be able to deal with the typepal source dependency of the rascal project --- src/org/rascalmpl/library/Messages.java | 8 ++-- src/org/rascalmpl/library/util/Eval.java | 5 +-- .../rascalmpl/library/util/PathConfig.java | 15 ++++++- .../shell/ShellEvaluatorFactory.java | 19 +++++--- .../infrastructure/RascalJUnitTestRunner.java | 9 ++-- .../tutor/repl/TutorCommandExecutor.java | 44 +++++++++---------- .../uri/project/ProjectURIResolver.java | 31 ++++++++----- .../uri/project/TargetURIResolver.java | 25 ++++++----- 8 files changed, 94 insertions(+), 62 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index 488f26c6e20..b3f2ca00607 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -115,15 +115,17 @@ else if (l2.hasOffsetLength()) { col = loc.getBeginColumn(); line = loc.getBeginLine(); } + boolean emptyPath = loc.getPath().isEmpty() || "/".equals(loc.getPath()); String output - = loc.getPath() - + ":" + = emptyPath + ? (((IString) msg.get("msg")).getValue()) + : (loc.getPath() + ":" + String.format("%0" + lineWidth + "d", line) + ":" + String.format("%0" + colWidth + "d", col) + ": " - + ((IString) msg.get("msg")).getValue() + + ((IString) msg.get("msg")).getValue()) ; if (isError) { diff --git a/src/org/rascalmpl/library/util/Eval.java b/src/org/rascalmpl/library/util/Eval.java index 729b9c84bc3..6bac6f39edf 100644 --- a/src/org/rascalmpl/library/util/Eval.java +++ b/src/org/rascalmpl/library/util/Eval.java @@ -229,10 +229,9 @@ public RascalRuntime(PathConfig pcfg, Reader input, PrintWriter stderr, PrintWri if (!pcfg.getSrcs().isEmpty()) { ISourceLocation projectRoot = inferProjectRoot((ISourceLocation) pcfg.getSrcs().get(0)); - String projectName = new RascalManifest().getProjectName(projectRoot); URIResolverRegistry reg = URIResolverRegistry.getInstance(); - reg.registerLogical(new ProjectURIResolver(projectRoot, projectName)); - reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); + reg.registerLogical(new ProjectURIResolver(projectRoot)); + reg.registerLogical(new TargetURIResolver(projectRoot)); } for (IValue path : pcfg.getSrcs()) { diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 7b632c4c7ff..2d0e231a446 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -466,6 +466,14 @@ public static PathConfig fromSourceProjectRascalManifest(ISourceLocation manifes IListWriter srcsWriter = vf.listWriter(); IListWriter messages = vf.listWriter(); + try { + // try to resolve cwd:/// and home:// and such to be able to find the folder name later. + manifestRoot = URIResolverRegistry.getInstance().logicalToPhysical(manifestRoot); + } + catch (IOException e) { + messages.append(Messages.error(e.getMessage(), manifestRoot)); + } + if (!projectName.equals("rascal")) { // always add the standard library but not for the project named "rascal" // which contains the source of the standard library @@ -631,7 +639,7 @@ else if (rascalProject != null) { } try { - addRascalToSourcePath(projectName, srcsWriter); + addRascalToSourcePath(projectName, srcsWriter, messages); } catch (IOException e) { messages.append(Messages.error(e.getMessage(), getRascalMfLocation(manifestRoot))); @@ -682,7 +690,7 @@ else if (rascalProject != null) { * one of the following is the case: (a) the current `rascal` can't be * resolved; (b) the TypePal jar isn't on the class path. */ - private static void addRascalToSourcePath(String projectName, IListWriter srcsWriter) throws IOException { + private static void addRascalToSourcePath(String projectName, IListWriter srcsWriter, IListWriter messages) throws IOException { // General case srcsWriter.append(URIUtil.rootLocation("std")); @@ -701,6 +709,9 @@ private static void addRascalToSourcePath(String projectName, IListWriter srcsWr srcsWriter.append(URIUtil.getChildLocation(workspaceRascal, "src/org/rascalmpl/compiler")); srcsWriter.append(URIUtil.getChildLocation(workspaceTypepal, "src")); } + else if (workspaceRascalExists && !workspaceTypepalExists) { + messages.append(Messages.warning("project://typepal/ was not found, but it is required for maintaining the compiler.", workspaceRascal)); + } // Special case: If the path config's project is `rascal-lsp`, and // `rascal` or `typepal` isn't open in the workspace, then use the diff --git a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java index 493ad4caa74..2c68320e782 100644 --- a/src/org/rascalmpl/shell/ShellEvaluatorFactory.java +++ b/src/org/rascalmpl/shell/ShellEvaluatorFactory.java @@ -1,6 +1,7 @@ package org.rascalmpl.shell; import java.io.File; +import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.net.URISyntaxException; @@ -10,7 +11,6 @@ import org.rascalmpl.interpreter.env.GlobalEnvironment; import org.rascalmpl.interpreter.env.ModuleEnvironment; import org.rascalmpl.interpreter.load.StandardLibraryContributor; -import org.rascalmpl.interpreter.utils.RascalManifest; import org.rascalmpl.library.Messages; import org.rascalmpl.library.util.PathConfig; import org.rascalmpl.library.util.PathConfig.RascalConfigMode; @@ -21,6 +21,7 @@ import org.rascalmpl.uri.project.TargetURIResolver; import org.rascalmpl.values.ValueFactoryFactory; +import io.usethesource.vallang.IListWriter; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; @@ -67,11 +68,16 @@ public static Evaluator getDefaultEvaluatorForLocation(File fileOrFolderInProjec } public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocation projectRoot) { - URIResolverRegistry reg = URIResolverRegistry.getInstance(); - - String projectName = new RascalManifest().getProjectName(projectRoot); - reg.registerLogical(new ProjectURIResolver(projectRoot, projectName)); - reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); + IListWriter messages = evaluator.getValueFactory().listWriter(); + + try { + URIResolverRegistry reg = URIResolverRegistry.getInstance(); + reg.registerLogical(new ProjectURIResolver(projectRoot)); + reg.registerLogical(new TargetURIResolver(projectRoot)); + } + catch (IOException e) { + messages.append(Messages.error(e.getMessage(), projectRoot)); + } PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPRETER); @@ -82,6 +88,7 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); evaluator.addClassLoader(cl); + Messages.write(messages.done(), evaluator.getOutPrinter()); Messages.write(pcfg.getMessages(), evaluator.getOutPrinter()); } } diff --git a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java index 202cbd1481b..2c049aab4dc 100644 --- a/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java +++ b/src/org/rascalmpl/test/infrastructure/RascalJUnitTestRunner.java @@ -93,11 +93,11 @@ public RascalJUnitTestRunner(Class clazz) { public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocation projectRoot) { URIResolverRegistry reg = URIResolverRegistry.getInstance(); - String projectName = new RascalManifest().getProjectName(projectRoot); - reg.registerLogical(new ProjectURIResolver(projectRoot, projectName)); - reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); try { + reg.registerLogical(new ProjectURIResolver(projectRoot)); + reg.registerLogical(new TargetURIResolver(projectRoot)); + PathConfig pcfg = PathConfig.fromSourceProjectRascalManifest(projectRoot, RascalConfigMode.INTERPRETER); for (IValue path : pcfg.getSrcs()) { @@ -110,6 +110,9 @@ public static void configureProjectEvaluator(Evaluator evaluator, ISourceLocatio Messages.write(pcfg.getMessages(), evaluator.getOutPrinter()); } + catch (IOException e) { + Messages.write(evaluator.getValueFactory().list(Messages.error(e.getMessage(), projectRoot)), evaluator.getOutPrinter()); + } catch (AssertionError e) { e.printStackTrace(); throw e; diff --git a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java index a11cd3a7f16..eb74f3add24 100644 --- a/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java +++ b/src/org/rascalmpl/tutor/lang/rascal/tutor/repl/TutorCommandExecutor.java @@ -19,7 +19,6 @@ import org.rascalmpl.debug.IRascalMonitor; import org.rascalmpl.ideservices.IDEServices; import org.rascalmpl.interpreter.Evaluator; -import org.rascalmpl.interpreter.utils.RascalManifest; import org.rascalmpl.interpreter.utils.ReadEvalPrintDialogMessages; import org.rascalmpl.library.util.PathConfig; import org.rascalmpl.parser.gtd.exception.ParseError; @@ -56,31 +55,30 @@ protected Evaluator buildEvaluator(Reader input, PrintWriter stdout, PrintWriter try { eval.getConfiguration().setRascalJavaClassPathProperty(PathConfig.resolveCurrentRascalRuntimeJar().getPath()); - } - catch (IOException e) { - services.warning(e.getMessage(), URIUtil.rootLocation("unknown")); - } - - if (!pcfg.getSrcs().isEmpty()) { - ISourceLocation projectRoot = inferProjectRoot((ISourceLocation) pcfg.getSrcs().get(0)); - String projectName = new RascalManifest().getProjectName(projectRoot); - URIResolverRegistry reg = URIResolverRegistry.getInstance(); - reg.registerLogical(new ProjectURIResolver(projectRoot, projectName)); - reg.registerLogical(new TargetURIResolver(projectRoot, projectName)); - - for (IValue path : pcfg.getSrcs()) { - eval.addRascalSearchPath((ISourceLocation) path); + + if (!pcfg.getSrcs().isEmpty()) { + ISourceLocation projectRoot = inferProjectRoot((ISourceLocation) pcfg.getSrcs().get(0)); + URIResolverRegistry reg = URIResolverRegistry.getInstance(); + reg.registerLogical(new ProjectURIResolver(projectRoot)); + reg.registerLogical(new TargetURIResolver(projectRoot)); + + for (IValue path : pcfg.getSrcs()) { + eval.addRascalSearchPath((ISourceLocation) path); + } + + for (IValue path : pcfg.getLibs()) { + eval.addRascalSearchPath((ISourceLocation) path); + } + + ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); + eval.addClassLoader(cl); } - - for (IValue path : pcfg.getLibs()) { - eval.addRascalSearchPath((ISourceLocation) path); + else { + services.warning("No src path configured for tutor", URIUtil.rootLocation("unknown")); } - - ClassLoader cl = new SourceLocationClassLoader(pcfg.getLibsAndTarget(), ShellEvaluatorFactory.class.getClassLoader()); - eval.addClassLoader(cl); } - else { - services.warning("No src path configured for tutor", URIUtil.rootLocation("unknown")); + catch (IOException e) { + services.warning(e.getMessage(), URIUtil.rootLocation("unknown")); } return eval; diff --git a/src/org/rascalmpl/uri/project/ProjectURIResolver.java b/src/org/rascalmpl/uri/project/ProjectURIResolver.java index 4024908860b..f7b329df5d0 100644 --- a/src/org/rascalmpl/uri/project/ProjectURIResolver.java +++ b/src/org/rascalmpl/uri/project/ProjectURIResolver.java @@ -15,6 +15,7 @@ import java.io.IOException; import org.rascalmpl.uri.ILogicalSourceLocationResolver; +import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; import io.usethesource.vallang.ISourceLocation; @@ -23,23 +24,33 @@ * This class implements the project:// scheme for in situations outside of an IDE. * In IDE based situations the IDE bridge must offer the implementation of the project * scheme. + * + * We take the root of the *active* project: + * * its parent is the "workspace" + * * all folders in the workspace are "projects" */ public class ProjectURIResolver implements ILogicalSourceLocationResolver { - private ISourceLocation root; - private String name; + private ISourceLocation workspaceFolder; - public ProjectURIResolver(ISourceLocation root, String name) { - this.root = root; - this.name = name; + /** + * @param projectRoot the root of a project, containing /META-INF/RASCAL.MF and /pom.xml + * @throws IOException if the parent of the root of a project does not exist + */ + public ProjectURIResolver(ISourceLocation projectRoot) throws IOException { + var physical = URIResolverRegistry.getInstance().logicalToPhysical(projectRoot); + this.workspaceFolder = URIUtil.getParentLocation(physical); } @Override public ISourceLocation resolve(ISourceLocation input) throws IOException { - if (!input.getAuthority().equals(name)) { - return null; - } + assert input.getScheme().equals(scheme()); + assert !input.getAuthority().isEmpty(); - return URIUtil.getChildLocation(root, input.getPath()); + // the authority becomes the folder name + var projectRoot = URIUtil.getChildLocation(workspaceFolder, input.getAuthority()); + + // the path becomes a child of the project's root + return URIUtil.getChildLocation(projectRoot, input.getPath()); } @Override @@ -49,6 +60,6 @@ public String scheme() { @Override public String authority() { - return name; + return ""; } } diff --git a/src/org/rascalmpl/uri/project/TargetURIResolver.java b/src/org/rascalmpl/uri/project/TargetURIResolver.java index 05de9f3d669..1c3bec59440 100644 --- a/src/org/rascalmpl/uri/project/TargetURIResolver.java +++ b/src/org/rascalmpl/uri/project/TargetURIResolver.java @@ -13,8 +13,8 @@ package org.rascalmpl.uri.project; import java.io.IOException; +import java.net.URISyntaxException; -import org.rascalmpl.uri.ILogicalSourceLocationResolver; import org.rascalmpl.uri.URIResolverRegistry; import org.rascalmpl.uri.URIUtil; @@ -25,13 +25,11 @@ * In IDE based situations the IDE bridge must offer the implementation of the project * scheme. */ -public class TargetURIResolver implements ILogicalSourceLocationResolver { - private ISourceLocation root; - private String name; +public class TargetURIResolver extends ProjectURIResolver { + - public TargetURIResolver(ISourceLocation root, String name) { - this.root = guessTarget(root); - this.name = name; + public TargetURIResolver(ISourceLocation root) throws IOException { + super(root); } private ISourceLocation guessTarget(ISourceLocation root) { @@ -59,11 +57,14 @@ private ISourceLocation guessTarget(ISourceLocation root) { @Override public ISourceLocation resolve(ISourceLocation input) throws IOException { - if (!input.getAuthority().equals(name)) { - return null; + try { + var root = super.resolve(URIUtil.changePath(input, "")); + var target = guessTarget(root); + return URIUtil.getChildLocation(target, input.getPath()); + } + catch (URISyntaxException e) { + throw new IOException(e); } - - return URIUtil.getChildLocation(root, input.getPath()); } @Override @@ -73,6 +74,6 @@ public String scheme() { @Override public String authority() { - return name; + return ""; } }