diff --git a/src/org/rascalmpl/library/IO.rsc b/src/org/rascalmpl/library/IO.rsc index 5e3255b4f67..e696f4e5a6c 100644 --- a/src/org/rascalmpl/library/IO.rsc +++ b/src/org/rascalmpl/library/IO.rsc @@ -18,6 +18,7 @@ The following input/output functions are defined: module IO import Exception; + extend analysis::diff::edits::FileSystemChanges; @synopsis{All functions in this module that have a charset parameter use this as default.} @@ -209,7 +210,6 @@ exists(|std:///IO.rsc|); @javaClass{org.rascalmpl.library.Prelude} public java bool exists(loc file); - @synopsis{Find a named file in a list of locations.} @examples{ ```rascal-shell diff --git a/src/org/rascalmpl/library/lang/rascal/grammar/definition/Modules.rsc b/src/org/rascalmpl/library/lang/rascal/grammar/definition/Modules.rsc index 240490bb805..ae0ace03a04 100644 --- a/src/org/rascalmpl/library/lang/rascal/grammar/definition/Modules.rsc +++ b/src/org/rascalmpl/library/lang/rascal/grammar/definition/Modules.rsc @@ -18,6 +18,8 @@ import Set; import IO; import util::Monitor; +private loc here = |std:///lang/rascal/syntax/grammar/definition/Modules|; + @memo @synopsis{Converts internal module representation of Rascal interpreter to single grammar definition} public Grammar modules2grammar(str main, map[str name, tuple[set[str] imports, set[str] extends, set[SyntaxDefinition] defs] \mod] mods) { @@ -51,17 +53,22 @@ public Grammar fuse(GrammarDefinition def) { done = {}; deps = dependencies(def); + if (!def.modules[def.main]?) { + jobWarning("the main module is unavailable (ignored)", here); + } + while (todo != {}) { = takeOneFrom(todo); done += nm; - if(def.modules[nm]?){ - \mod = def.modules[nm]; - result = (compose(result, \mod.grammar) | compose(it, def.modules[i].grammar) | i <- deps[nm], def.modules[i]?); - todo += (\mod.extends - done); - } - else { - warning("Fuse algorithm misses module definition for dependency ", |unknown:///|); + + \mod = def.modules[nm]; + + for (str i <- deps[nm], !def.modules[i]?) { + jobWarning(" imports or extends the unavailable module (ignored)", here); } + + result = (compose(result, \mod.grammar) | compose(it, def.modules[i].grammar) | i <- deps[nm], def.modules[i]?); + todo += (\mod.extends - done); } return result; @@ -69,6 +76,7 @@ public Grammar fuse(GrammarDefinition def) { + public GrammarModule module2grammar(Module \mod) { = getModuleMetaInf(\mod); return \module(nm, imps, exts, syntax2grammar(collect(\mod))); diff --git a/src/org/rascalmpl/library/lang/rascal/grammar/storage/ModuleParserStorage.rsc b/src/org/rascalmpl/library/lang/rascal/grammar/storage/ModuleParserStorage.rsc index 88b36c12a3a..10bcaeae2f4 100644 --- a/src/org/rascalmpl/library/lang/rascal/grammar/storage/ModuleParserStorage.rsc +++ b/src/org/rascalmpl/library/lang/rascal/grammar/storage/ModuleParserStorage.rsc @@ -102,13 +102,26 @@ int main(list[str] args) { storeParsersForModules(pcfg); } ``` + +Or, you could use the ((PathConfig)) parameter feature of `main` functions. The Rascal maven plugin will +make sure to pass the proper ((PathConfig)) parameter to your main function: +```rascal +module YourMainModule + +import util::Reflective; +import lang::rascal::grammar::storage::ModuleParserStorage; + +int main(PathConfig pcfg = pathConfig()) { + storeParsersForModules(pcfg); +} +``` } void storeParsersForModules(PathConfig pcfg) { - storeParsersForModules({*find(src, "rsc") | src <- pcfg.srcs, bprintln("Crawling ")}, pcfg); + storeParsersForModules({*find(src, "rsc", exclude={*pcfg.ignores}, checkExist=true) | src <- pcfg.srcs, bprintln("Crawling ")}, pcfg); } void storeParsersForModules(set[loc] moduleFiles, PathConfig pcfg) { - storeParsersForModules({parseModule(m) | m <- moduleFiles, bprintln("Loading ")}, pcfg); + storeParsersForModules({parseModule(m) | m <- moduleFiles, m notin pcfg.ignores, bprintln("Loading ")}, pcfg); } void storeParsersForModules(set[Module] modules, PathConfig pcfg) { diff --git a/src/org/rascalmpl/library/util/FileSystem.rsc b/src/org/rascalmpl/library/util/FileSystem.rsc index 4c124b764ce..18ad29c5a3f 100644 --- a/src/org/rascalmpl/library/util/FileSystem.rsc +++ b/src/org/rascalmpl/library/util/FileSystem.rsc @@ -7,35 +7,94 @@ } module util::FileSystem +import Exception; import IO; +import util::Monitor; +@synopsis{Model of a file system with its (nested) files and directories} data FileSystem = directory(loc l, set[FileSystem] children) | file(loc l) ; -FileSystem crawl(loc l) = isDirectory(l) ? directory(l, {crawl(e) | e <- l.ls}) : file(l); +@synopsis{Extract a compositional ((FileSystem)) model starting from a given directory location.} +@description{ +* Using `exclude` you can avoid going into certain directories or filter specific files from the result. +* With `checkExist=true` the `l` parameter is checked to exist before the file system is crawled and a PathNotFound exception is thrown if not. +} +FileSystem crawl(loc l, set[loc] exclude= {}, bool checkExist=false) throws PathNotFound + = isDirectory(l) ? directory(l, {crawl(e, exclude=exclude, checkExist=false) | e <- l.ls, l notin exclude}) : file(l) + when checkExist ==> throwNotExist(l) + ; -@synopsis{Recursively lists locations of all files from the supplied directory. - If input is a file, its location is returned instead.} -set[loc] files(loc l) = isDirectory(l) ? { *files(e) | e <- l.ls } : {l}; +@synopsis{Recursively lists locations of all files from the supplied directory.} +@description{ +* If input `l` is a file, its location is returned instead. +* Using `exclude` you can avoid going into certain directories or filter specific files from the result. +* With `checkExist=true` the `l` parameter is checked to exist before the file system is crawled and a PathNotFound exception is thrown if not. +} +set[loc] files(loc l, set[loc] exclude={}, bool checkExist=false) throws PathNotFound + = isDirectory(l) ? { *files(e, exclude=exclude, checkExist=false) | e <- l.ls, e notin exclude} : {l} + when checkExist ==> throwNotExist(l); -@synopsis{Recursively lists locations of all files that satisfy the filter criterion `filt`. - For a file to be included, `filt` must return `true` for it.} -set[loc] find(loc f, bool (loc) filt) +@synopsis{Recursively lists locations of all files that satisfy the filter criterion `filt`.} +@description{ +* For a file to be included, `filt` must return `true` for it. All directories are traversed though, regardless of `filt`. +* Using `exclude` you can avoid going into certain directories or filter specific files from the result. +* With `checkExist=true` the `f` parameter is checked to exist before the file system is crawled and a PathNotFound exception is thrown if not. +} +set[loc] find(loc f, bool (loc) filt, set[loc] exclude = {}, bool checkExist=false) throws PathNotFound = isDirectory(f) - ? {*find(c, filt) | c <- f.ls} + (filt(f) ? {f} : { }) + ? {*find(c, filt, exclude=exclude, checkExist=false) | c <- f.ls, c notin exclude} + ((filt(f) && f notin exclude) ? {f} : { }) : (filt(f) ? {f} : { }) + when checkExist ==> throwNotExist(f) ; @synopsis{Recursively lists locations of all files that end in `ext`.} -set[loc] find(loc f, str ext) = find(f, bool (loc l) { return l.extension == ext; }); +@description{ +* For a file to be included, it's extension must equal `ext`. All directories are traversed though, regardless of their extension. +* Using `exclude` you can avoid going into certain directories or filter specific files from the result. +* With `checkExist=true` the `f` parameter is checked to exist before the file system is crawled and a PathNotFound exception is thrown if not. +} +set[loc] find(loc f, str ext, set[loc] exclude={}, bool checkExist=false) throws PathNotFound + = find(f, bool (loc l) { return l.extension == ext; }, exclude=exclude, checkExist=checkExist); @synopsis{Lists all files recursively ignored files and directories starting with a dot.} -set[loc] visibleFiles(loc l) { - if (/^\./ := l.file) +set[loc] visibleFiles(loc l, bool checkExist=false) throws PathNotFound { + if (checkExist) { + throwNotExist(l); + } + if (/^\./ := l.file) { return {}; - if (isDirectory(l)) - return {*visibleFiles(f) | f <- l.ls}; + } + if (isDirectory(l)) { + return {*visibleFiles(f, checkExist=false) | f <- l.ls}; + } return {l}; } + +@synopsis{Always returns true, but shows a ((util::Monitor::jobWarning)) if `file` does not exist.} +@benefits{ +* This can be used practically in comprehensions that process file locations. +* Use it to fail more transparantly, but still in case of erroneous file configuration (paths) +} +bool warnNotExist(loc file) { + if (!exists(file)) { + jobWarning(" does not exist.", |std:///util/FileSystem|); + } + return true; +} + +@synopsis{Always returns true, except when throwing FileNotFound if `file` does not exist} +@benefits{ +* This can be used practically in comprehensions that process file locations; +* Use it to fail faster and harder in case of erroneous file configuration (paths) +} +bool throwNotExist(loc file) throws PathNotFound { + if (!exists(file)) { + throw PathNotFound(file); + } + return true; +} + +