Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Location;
import analysis::graphs::Graph;
import util::FileSystem;
import util::Monitor;
import util::ParseErrorRecovery;
import util::Reflective;

import lang::rascal::\syntax::Rascal;
Expand All @@ -53,38 +54,65 @@ import lang::rascalcore::check::ModuleLocations;
}
map[loc, set[Message]] checkFile(loc l, set[loc] workspaceFolders, start[Module](loc file) getParseTree, PathConfig(loc file) getPathConfig)
= job("Rascal check", map[loc, set[Message]](void(str, int) step) {
checkForImports = [getParseTree(l)];
openFile = (start[Module]) `module Placeholder`;
try {
// Note: check further down parses again, possibly leading to a different tree if the contents changed in the meantime
openFile = getParseTree(l);
} catch ParseError(loc err): {
return ();
}
if (hasParseErrors(openFile)) {
// We cannot typecheck this file, since it has type errors. Do not return any errors, since the parse triggered by the IDE will take care of that.
return ();
}
openFileHeader = openFile.top.header.name;

checkForImports = [openFile];
checkedForImports = {};
initialProject = inferProjectRoot(l);

rel[loc, loc] dependencies = {};

step("Dependency graph", 1);
job("Building dependency graph", bool (void (str, int) step2) {
parseMsgs = job("Building dependency graph", map[loc, set[Message]] (void (str, int) step2) {
while (tree <- checkForImports) {
step2("Calculating imports for <tree.top.header.name>", 1);
currentSrc = tree.src.top;
currentProject = inferProjectRoot(currentSrc);
if (currentProject in workspaceFolders && currentProject.file notin {"rascal", "rascal-lsp"}) {
for (i <- tree.top.header.imports, i has \module) {
modName = "<i.\module>";
try {
ml = locateRascalModule("<i.\module>", getPathConfig(currentProject), getPathConfig, workspaceFolders);
ml = locateRascalModule(modName, getPathConfig(currentProject), getPathConfig, workspaceFolders);
if (ml.extension == "rsc", mlpt := getParseTree(ml), mlpt.src.top notin checkedForImports) {
if (hasParseErrors(mlpt)) {
return (l: {error("Cannot typecheck this module, since dependency `<modName>` has parse error(s).", openFileHeader.src,
causes=[error("Has a parse error around this position.", e.src) | Tree e <- findBestParseErrors(mlpt)])
});
}
checkForImports += mlpt;
jobTodo("Building dependency graph");
dependencies += <currentProject, inferProjectRoot(mlpt.src.top)>;
}
} catch _: {
} catch ParseError(loc err): {
return (l: {error("Cannot typecheck this module, since dependency `<modName>` has parse error(s).", openFileHeader.src, causes=[error("Has parse error(s).", err)])});
} catch e: {
println("Exception while building dependency graph at <currentSrc>: <e>");
;// Continue
}
}
}
checkedForImports += currentSrc;
checkForImports -= tree;
}
return true;

return ();
}, totalWork=1);

if (() != parseMsgs) {
return parseMsgs;
}

cyclicDependencies = {p | <p, p> <- (dependencies - ident(carrier(dependencies)))+};
if (cyclicDependencies != {}) {
return (l : {error("Cyclic dependencies detected between projects {<intercalate(", ", [*cyclicDependencies])>}. This is not supported. Fix your project setup.", l)});
Expand Down
Loading